获取RichEditCtrl图片及如何使用在你的程序中~

来源:互联网 发布:php pdo sqlserver 编辑:程序博客网 时间:2024/05/29 04:46

1. How To Get Image Out of RichEditCtrl (Plus writing to bitmap file):

//Suppose you are using MFC, You doIRichEditOle* pReo = m_pRichEdit->GetIRichEditOle( );//If you use Platform SDK directlyIRichEditOle* pReo;::SendMessage(g_hYourRichEdit, EM_GETOLEINTERFACE,  0, (LPARAM)(LPVOID*)&pReo);//Note: in both cases, inside pReo's AddRef got called, so//remember to release it laterLONG nNumber = pReo->GetObjectCount();  //Your Images' Number//Handle Error yourself, code simplified for space limitationfor(int i = 0; i < nNumber; i++){  REOBJECT* ro = new REOBJECT;  ro->cbStruct = sizeof(REOBJECT);  HRESULT hr = pReo->GetObject(i, ro, REO_GETOBJ_ALL_INTERFACES);  if(FAILED(hr)) continue;  //caller should released the inner object  IDataObject* lpDataObject;  hr = (ro->poleobj)->QueryInterface(IID_IDataObject,       (void **)&lpDataObject);  if(FAILED(hr)) continue;  STGMEDIUM stgm;  //out  FORMATETC fm;    //in  fm.cfFormat = CF_DIB;  // Clipboard format  fm.ptd = NULL;         // Target Device = Screen  fm.dwAspect = DVASPECT_CONTENT;                         // Level of detail = Full content  fm.lindex = -1;        // Index = Not applicaple  fm.tymed = TYMED_HGLOBAL ;  hr = lpDataObject->GetData(&fm, &stgm);  if(FAILED(hr)) continue;  ASSERT(::GlobalSize(stgm.hGlobal));  HANDLE hFile = ::CreateFile(_T("c:\\img.bmp"),                 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,                 FILE_ATTRIBUTE_NORMAL, NULL);  if(hFile == INVALID_HANDLE_VALUE)  { continie; }  DWORD dwWritten;  //Writing Bitmap File header  BITMAPFILEHEADER bmfh;  bmfh.bfType = 0x4d42;    //'BM'  int nColorTableEntries = 0;  int nSizeHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) *                 nColorTableEntries;  bmfh.bfSize = 0;  bmfh.bfReserved1 = bmfh.bfReserved2 = 0;  bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) +                   sizeof(BITMAPINFOHEADER) +                   sizeof(RGBQUAD) * nColorTableEntries;  ::WriteFile(hFile, (LPVOID)&bmfh, sizeof(BITMAPFILEHEADER),                             &dwWritten, NULL);  DWORD dwGlobalSize = ::GlobalSize(stgm.hGlobal);  LPVOID lpMem = ::VirtualAlloc(NULL, dwGlobalSize, MEM_COMMIT,                                      PAGE_READWRITE);  ::CopyMemory(lpMem, (LPVOID)::GlobalLock(stgm.hGlobal),                                           dwGlobalSize);  BITMAPINFOHEADER* pInfoHead = (BITMAPINFOHEADER*)lpMem;  pInfoHead->biXPelsPerMeter = pInfoHead->biYPelsPerMeter                                = 0;  //Special Careful Here!!! Discard the Color Mask,  //We need TRUE COLOR image  //I bellieve you guys running Win2X/Xp use true color  //screen setting  if(pInfoHead->biCompression == BI_BITFIELDS)  {    pInfoHead->biCompression = BI_RGB;    dwGlobalSize -= 3 * sizeof(RGBQUAD);  //delete the 3 DWORD                                          //color mask    LPBYTE pSrc, pDst;    pSrc = (LPBYTE)lpMem;    pSrc += sizeof(BITMAPINFOHEADER);    pDst = pSrc;    pSrc += 3 * sizeof(RGBQUAD);    ::MoveMemory(pDst, pSrc, dwGlobalSize -                 sizeof(BITMAPINFOHEADER));  }  //Write Image Data  ::WriteFile(hFile, lpMem, dwGlobalSize, &dwWritten, NULL);  ::GlobalUnlock(stgm.hGlobal);  //You may find good if all image are same size, keeping the  //memory for performance  ::VirtualFree(lpMem, 0, MEM_RELEASE);  ::CloseHandle(hFile);  lpDataObject->Release();  delete ro;}pReo->Release();

2. How Do You Transfer Data from Messenger to Your Own Program?

To achieve best performance, I use 2 Memory Map File and 4 Events to synchronize the RTF data and the image data respectively. All these kernel objects are named as a GUID to avoid name confliction. In the program side, when the frame starts, I make all initializations like these:

m_hMMF = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,  PAGE_READWRITE, 0, MsnPage, GUID_MMF_NAME);if (m_hMMF == NULL){    // handle error here}LPVOID pView = MapViewOfFile(m_hMMF, FILE_MAP_WRITE, 0, 0, 0);DWORD dwSize = YourMMFSize;DWORD dwUsed = 0;LPBYTE lpByte = (LPBYTE)pView;::memcpy(lpByte, &dwSize, 4);::memcpy(lpByte + 4, &dwUsed, 4);  //Now both sides knows the MMF size::UnmapViewOfFile(pView);m_hReadEvent = ::CreateEvent(NULL, TRUE, FALSE,                             GUID_READ_EVENT_NAME);if(m_hReadEvent == NULL){    //handle error}m_hWriteEvent = ::CreateEvent(NULL, TRUE, FALSE,                              GUID_WRITE_EVENT_NAME);if(m_hWriteEvent == NULL){    //handle error}::ResetEvent(m_hReadEvent);::SetEvent(m_hWriteEvent); //Important Here, If not set,                           //you get deadlock forever//Note: data is unidirectional from DLL to frame, so DLL//can begin to write now//create my frame thread ...

In frame side thread, it reads data sent from Hook DLL only:

//in thread part:__try{  hMMF = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE,                         GUID_MSG_MMF_NAME);  if (hMMF == NULL)    //error    __leave;  hWriteEvent = ::OpenEvent(EVENT_ALL_ACCESS,                            FALSE,GUID_MSG_WRITE_EVENT_NAME);  if(hWriteEvent == NULL)    __leave;  hReadEvent = ::OpenEvent(EVENT_ALL_ACCESS,                           FALSE,g_MSG_READ_EVENT_NAME);  if(hReadEvent == NULL) __leave;  ::SetEvent(hWriteEvent);    //Just a reminder  HANDLE hReadArr[2];  hReadArr[0] = hKillThreadEvent;  hReadArr[1] = hReadEvent;  while(1)  {    DWORD dwRet = ::WaitForMultipleObjects(2, hReadArr, FALSE,                                           1000);    if(WAIT_OBJECT_0 == dwRet) __leave;    if(dwRet == WAIT_TIMEOUT) continue;    if(dwRet == WAIT_ABANDONED_0 || dwRet == WAIT_ABANDONED_0 + 1)    __leave;    ASSERT((WAIT_OBJECT_0 + 1) == dwRet);    ::ResetEvent(hReadEvent);    LPVOID pView = MapViewOfFile(hMMF, FILE_MAP_ALL_ACCESS,                                 0, 0, 0);    if(pView == NULL) __leave;    LPBYTE lpByte = (LPBYTE)pView;    //Enjoy Your Data here!!!!    ::UnmapViewOfFile(pView);    ::SetEvent(hWriteEvent);  }}__finally {  ::CloseHandle(hMMF);  ::CloseHandle(hWriteEvent);  ::CloseHandle(hReadEvent);    // and other stuff....}

In the Hook DLL part, you just exchange the position of the read and write event, and you do not need the loop because the DLL is message driven; besides, you set the wait time in the DLL to zero because the data is sent passively from the DLL while the frame thread running in wait loop. This structure will ensure the MMF is accessed by only one thread at one time. And in my point of view, WM_COPYMESSAGE (Spy++ uses this method), though theoretically able to realize the data transferring functionality, should be avoided; the reason is compatibility and portablity. In my case, this program has been ported to an NT Service to monitor the Messenger, which has no window at all to pursue maximum stability and performance. Besides, even in a Windows application like this, considering the performance, if my frame thread is blocked temporarily by some GUI action, the DLL thread can still write data to the MMF until it is full, and once the frame thread gets a chance to run, it can fetch all the previous data and empty the MMF. Actually, in my last project, the DLL can make a larger MMF and copy the data there, free the old MMF, and wait the receiving thread to wake. All this means better fault tolerance, stability, and performance of the program.