📄 misc.c
字号:
GlobalUnlock((HGLOBAL)hData); } return ret;}/* ================================================================ * * Global <=> Data handle management * * ================================================================ *//* Note: we use a DDEDATA, but layout of DDEDATA, DDEADVISE and DDEPOKE structures is similar: * offset size * (bytes) (bits) comment * 0 16 bit fields for options (release, ackreq, response...) * 2 16 clipboard format * 4 ? data to be used */HDDEDATA WDML_Global2DataHandle(HGLOBAL hMem, WINE_DDEHEAD* p){ DDEDATA* pDd; HDDEDATA ret = 0; DWORD size; if (hMem) { pDd = GlobalLock(hMem); size = GlobalSize(hMem) - sizeof(WINE_DDEHEAD); if (pDd) { if (p) memcpy(p, pDd, sizeof(WINE_DDEHEAD)); switch (pDd->cfFormat) { default: FIXME("Unsupported format (%d) for data... assuming raw information\n", pDd->cfFormat); /* fall thru */ case 0: case CF_TEXT: ret = DdeCreateDataHandle(0, pDd->Value, size, 0, 0, pDd->cfFormat, 0); break; case CF_BITMAP: if (size >= sizeof(BITMAP)) { BITMAP* bmp = (BITMAP*)pDd->Value; int count = bmp->bmWidthBytes * bmp->bmHeight * bmp->bmPlanes; if (size >= sizeof(BITMAP) + count) { HBITMAP hbmp; if ((hbmp = CreateBitmap(bmp->bmWidth, bmp->bmHeight, bmp->bmPlanes, bmp->bmBitsPixel, pDd->Value + sizeof(BITMAP)))) { ret = DdeCreateDataHandle(0, (LPBYTE)&hbmp, sizeof(hbmp), 0, 0, CF_BITMAP, 0); } else ERR("Can't create bmp\n"); } else { ERR("Wrong count: %lu / %d\n", size, sizeof(BITMAP) + count); } } else ERR("No bitmap header\n"); break; } GlobalUnlock(hMem); } } return ret;}/****************************************************************** * WDML_DataHandle2Global * * */HGLOBAL WDML_DataHandle2Global(HDDEDATA hDdeData, BOOL fResponse, BOOL fRelease, BOOL fDeferUpd, BOOL fAckReq){ DDE_DATAHANDLE_HEAD* pDdh; DWORD dwSize; HGLOBAL hMem = 0; dwSize = GlobalSize((HGLOBAL)hDdeData) - sizeof(DDE_DATAHANDLE_HEAD); pDdh = (DDE_DATAHANDLE_HEAD*)GlobalLock((HGLOBAL)hDdeData); if (dwSize && pDdh) { WINE_DDEHEAD* wdh = NULL; switch (pDdh->cfFormat) { default: FIXME("Unsupported format (%d) for data... passing raw information\n", pDdh->cfFormat); /* fall thru */ case 0: case CF_TEXT: hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(WINE_DDEHEAD) + dwSize); if (hMem && (wdh = GlobalLock(hMem))) { memcpy(wdh + 1, pDdh + 1, dwSize); } break; case CF_BITMAP: if (dwSize >= sizeof(HBITMAP)) { BITMAP bmp; DWORD count; HBITMAP hbmp = *(HBITMAP*)(pDdh + 1); if (GetObjectA(hbmp, sizeof(bmp), &bmp)) { count = bmp.bmWidthBytes * bmp.bmHeight; hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(WINE_DDEHEAD) + sizeof(bmp) + count); if (hMem && (wdh = GlobalLock(hMem))) { memcpy(wdh + 1, &bmp, sizeof(bmp)); GetBitmapBits(hbmp, count, ((char*)(wdh + 1)) + sizeof(bmp)); } } } break; } if (wdh) { wdh->unused = 0; wdh->fResponse = fResponse; wdh->fRelease = fRelease; wdh->fDeferUpd = fDeferUpd; wdh->fAckReq = fAckReq; wdh->cfFormat = pDdh->cfFormat; GlobalUnlock(hMem); } GlobalUnlock((HGLOBAL)hDdeData); } return hMem;}/* ================================================================ * * Server management * * ================================================================ *//****************************************************************** * WDML_AddServer * * */WDML_SERVER* WDML_AddServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTopic){ WDML_SERVER* pServer; char buf1[256]; char buf2[256]; pServer = (WDML_SERVER*)HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_SERVER)); if (pServer == NULL) return NULL; WDML_IncHSZ(pInstance, pServer->hszService = hszService); DdeQueryStringA(pInstance->instanceID, hszService, buf1, sizeof(buf1), CP_WINANSI); snprintf(buf2, sizeof(buf2), "%s(0x%08lx)", buf1, GetCurrentProcessId()); pServer->hszServiceSpec = DdeCreateStringHandleA(pInstance->instanceID, buf2, CP_WINANSI); pServer->atomService = WDML_MakeAtomFromHsz(pServer->hszService); pServer->atomServiceSpec = WDML_MakeAtomFromHsz(pServer->hszServiceSpec); pServer->filterOn = TRUE; pServer->next = pInstance->servers; pInstance->servers = pServer; return pServer;}/****************************************************************** * WDML_RemoveServer * * */void WDML_RemoveServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTopic){ WDML_SERVER* pPrev = NULL; WDML_SERVER* pServer = NULL; WDML_CONV* pConv; WDML_CONV* pConvNext; pServer = pInstance->servers; while (pServer != NULL) { if (DdeCmpStringHandles(pServer->hszService, hszService) == 0) { WDML_BroadcastDDEWindows(WDML_szEventClass, WM_WDML_UNREGISTER, pServer->atomService, pServer->atomServiceSpec); /* terminate all conversations for given topic */ for (pConv = pInstance->convs[WDML_SERVER_SIDE]; pConv != NULL; pConv = pConvNext) { pConvNext = pConv->next; if (DdeCmpStringHandles(pConv->hszService, hszService) == 0) { WDML_RemoveConv(pConv, WDML_SERVER_SIDE); /* don't care about return code (whether client window is present or not) */ PostMessageA(pConv->hwndClient, WM_DDE_TERMINATE, (WPARAM)pConv->hwndServer, 0L); } } if (pServer == pInstance->servers) { pInstance->servers = pServer->next; } else { pPrev->next = pServer->next; } DestroyWindow(pServer->hwndServer); WDML_DecHSZ(pInstance, pServer->hszServiceSpec); WDML_DecHSZ(pInstance, pServer->hszService); GlobalDeleteAtom(pServer->atomService); GlobalDeleteAtom(pServer->atomServiceSpec); HeapFree(GetProcessHeap(), 0, pServer); break; } pPrev = pServer; pServer = pServer->next; }}/***************************************************************************** * WDML_FindServer * * generic routine to return a pointer to the relevant ServiceNode * for a given service name, or NULL if the entry does not exist * */WDML_SERVER* WDML_FindServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTopic){ WDML_SERVER* pServer; for (pServer = pInstance->servers; pServer != NULL; pServer = pServer->next) { if (hszService == pServer->hszService) { return pServer; } } TRACE("Service name missing\n"); return NULL;}/* ================================================================ * * Conversation management * * ================================================================ *//****************************************************************** * WDML_AddConv * * */WDML_CONV* WDML_AddConv(WDML_INSTANCE* pInstance, WDML_SIDE side, HSZ hszService, HSZ hszTopic, HWND hwndClient, HWND hwndServer){ WDML_CONV* pConv; /* no converstation yet, add it */ pConv = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_CONV)); if (!pConv) return NULL; pConv->instance = pInstance; WDML_IncHSZ(pInstance, pConv->hszService = hszService); WDML_IncHSZ(pInstance, pConv->hszTopic = hszTopic); pConv->hwndServer = hwndServer; pConv->hwndClient = hwndClient; pConv->transactions = NULL; pConv->hUser = 0; pConv->wStatus = (side == WDML_CLIENT_SIDE) ? ST_CLIENT : 0L; /* check if both side of the conversation are of the same instance */ if (GetWindowThreadProcessId(hwndClient, NULL) == GetWindowThreadProcessId(hwndServer, NULL) && WDML_GetInstanceFromWnd(hwndClient) == WDML_GetInstanceFromWnd(hwndServer)) { pConv->wStatus |= ST_ISSELF; } pConv->wConvst = XST_NULL; pConv->next = pInstance->convs[side]; pInstance->convs[side] = pConv; return pConv;}/****************************************************************** * WDML_FindConv * * */WDML_CONV* WDML_FindConv(WDML_INSTANCE* pInstance, WDML_SIDE side, HSZ hszService, HSZ hszTopic){ WDML_CONV* pCurrent = NULL; for (pCurrent = pInstance->convs[side]; pCurrent != NULL; pCurrent = pCurrent->next) { if (DdeCmpStringHandles(pCurrent->hszService, hszService) == 0 && DdeCmpStringHandles(pCurrent->hszTopic, hszTopic) == 0) { return pCurrent; } } return NULL;}/****************************************************************** * WDML_RemoveConv * * */void WDML_RemoveConv(WDML_CONV* pRef, WDML_SIDE side){ WDML_CONV* pPrev = NULL; WDML_CONV* pCurrent; WDML_XACT* pXAct; WDML_XACT* pXActNext; HWND hWnd; if (!pRef) return; /* remove any pending transaction */ for (pXAct = pRef->transactions; pXAct != NULL; pXAct = pXActNext) { pXActNext = pXAct->next; WDML_FreeTransaction(pRef->instance, pXAct, TRUE); } WDML_RemoveAllLinks(pRef->instance, pRef, side); /* FIXME: should we keep the window around ? it seems so (at least on client side * to let QueryConvInfo work after conv termination, but also to implement * DdeReconnect... */ /* destroy conversation window, but first remove pConv from hWnd. * this would help the wndProc do appropriate handling upon a WM_DESTROY message */ hWnd = (side == WDML_CLIENT_SIDE) ? pRef->hwndClient : pRef->hwndServer; SetWindowLongA(hWnd, GWL_WDML_CONVERSATION, 0); DestroyWindow((side == WDML_CLIENT_SIDE) ? pRef->hwndClient : pRef->hwndServer); WDML_DecHSZ(pRef->instance, pRef->hszService); WDML_DecHSZ(pRef->instance, pRef->hszTopic); for (pCurrent = pRef->instance->convs[side]; pCurrent != NULL; pCurrent = (pPrev = pCurrent)->next) { if (pCurrent == pRef) { if (pCurrent == pRef->instance->convs[side]) { pRef->instance->convs[side] = pCurrent->next; } else { pPrev->next = pCurrent->next; } HeapFree(GetProcessHeap(), 0, pCurrent); break; } }}/****************************************************************** * WDML_EnableCallback */static BOOL WDML_EnableCallback(WDML_CONV *pConv, UINT wCmd){ if (wCmd == EC_DISABLE) { FIXME("EC_DISABLE is not implemented\n"); return TRUE; } if (wCmd == EC_QUERYWAITING) return pConv->transactions ? TRUE : FALSE; if (wCmd != EC_ENABLEALL && wCmd != EC_ENABLEONE) { FIXME("Unknown command code %04x\n", wCmd); return FALSE; } while (pConv->transactions) { WDML_XACT *pXAct = pConv->transactions; WDML_UnQueueTransaction(pConv, pXAct); if (pConv->wStatus & ST_CLIENT) { /*WDML_ClientHandle(pConv, pXAct);*/ FIXME("Client delayed transaction queue handling is not supported\n"); } else WDML_ServerHandle(pConv, pXAct); WDML_FreeTransaction(pConv->instance, pXAct, TRUE); if (wCmd == EC_ENABLEONE) break; } return TRUE;}/***************************************************************** * DdeEnableCallback (USER32.@) */BOOL WINAPI DdeEnableCallback(DWORD idInst, HCONV hConv, UINT wCmd){ BOOL ret = FALSE; WDML_CONV *pConv; TRACE("(%ld, %p, %04x)\n", idInst, hConv, wCmd); EnterCriticalSection(&WDML_CritSect); pConv = WDML_GetConv(hConv, TRUE); if (pConv && pConv->instance->instanceID == idInst) ret = WDML_EnableCallback(pConv, wCmd); LeaveCriticalSection(&WDML_CritSect); return ret;}/****************************************************************** * WDML_GetConv * * */WDML_CONV* WDML_GetConv(HCONV hConv, BOOL checkConnected){ WDML_CONV* pConv = (WDML_CONV*)hConv; /* FIXME: should do better checking */ if (pConv == NULL) return NULL; if (checkConnected && !(pConv->wStatus & ST_CONNECTED)) { FIXME("found conv but ain't connected\n"); return NULL; } if (GetCurrentThreadId() != pConv->instance->threadID) { FIXME("wrong thread ID\n"); return NULL; } return pConv;}/****************************************************************** * WDML_GetConvFromWnd * * */WDML_CONV* WDML_GetConvFromWnd(HWND hWnd){ return (WDML_CONV*)GetWindowLongA(hWnd, GWL_WDML_CONVERSATION);}/****************************************************************** * WDML_PostAck * * */BOOL WDML_PostAck(WDML_CONV* pConv, WDML_SIDE side, WORD appRetCode, BOOL fBusy, BOOL fAck, UINT pmt, LPARAM lParam, UINT oldMsg){ DDEACK ddeAck; HWND from, to; if (side == WDML_SERVER_SIDE) { from = pConv->hwndServer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -