BOOL __stdcall ProcessRequest(HWND hwnd, LPARAM param) { char szBuf[MAX_PATH]; TEnumData *lParam = (TEnumData*)param; DWORD pid = 0; GetWindowThreadProcessId(hwnd, &pid); if (pid != 0) { // old system would get a window's pid and the module handle that created it // and try to OpenEvent() a event object name to it (prefixed with a string) // this was fine for most Oses (not the best way) but now actually compares // the class string (a bit slower) but should get rid of those bugs finally. HANDLE hMirandaWorkEvent = OpenEventA(EVENT_ALL_ACCESS, false, CreateProcessUID(pid, szBuf, sizeof(szBuf))); if (hMirandaWorkEvent != 0) { GetClassNameA(hwnd, szBuf, sizeof(szBuf)); if ( lstrcmpA(szBuf, MIRANDACLASS) != 0) { // opened but not valid. logA("ProcessRequest(%d, %p): class %s differs from %s\n", pid, hwnd, szBuf, MIRANDACLASS); CloseHandle(hMirandaWorkEvent); return true; } } // if the event object exists, a shlext.dll running in the instance must of created it. if (hMirandaWorkEvent != 0) { logA("ProcessRequest(%d, %p): window found\n", pid, hwnd); // prep the request ipcPrepareRequests(IPC_PACKET_SIZE, lParam->ipch, REQUEST_ICONS | REQUEST_GROUPS | REQUEST_CONTACTS | REQUEST_NEWICONS); // slots will be in the order of icon data, groups contacts, the first // slot will contain the profile name DWORD replyBits = ipcSendRequest(hMirandaWorkEvent, lParam->hWaitFor, lParam->ipch, 1000); // replyBits will be REPLY_FAIL if the wait timed out, or it'll be the request // bits as sent or a series of *_NOTIMPL bits where the request bit were, if there are no // contacts to speak of, don't bother showing this instance of Miranda } if (replyBits != REPLY_FAIL && lParam->ipch->ContactsBegin != NULL) { logA("ProcessRequest(%d, %p): IPC succeeded\n", pid, hwnd); // load the address again, the server side will always overwrite it lParam->ipch->pClientBaseAddress = lParam->ipch; // fixup all the pointers to be relative to the memory map // the base pointer of the client side version of the mapped file ipcFixupAddresses(lParam->ipch); // store the PID used to create the work event object // that got replied to -- this is needed since each contact // on the final menu maybe on a different instance and another OpenEvent() will be needed. lParam->pid = pid; // check out the user options from the server lParam->bShouldOwnerDraw = (lParam->ipch->dwFlags & HIPC_NOICONS) == 0; // process the icons BuildSkinIcons(lParam); // process other replies BuildMenus(lParam); } // close the work object CloseHandle(hMirandaWorkEvent); } } return true; }
void __cdecl ThreadServer(HANDLE hMainThread) { char szBuf[100]; HANDLE hEvent = CreateEventA(NULL, false, false, CreateProcessUID(GetCurrentProcessId(), szBuf, sizeof(szBuf))); while (true) { int retVal = WaitForSingleObjectEx(hEvent, INFINITE, true); if (retVal == WAIT_OBJECT_0) QueueUserAPC(ipcService, hMainThread, 0); if (CallService(MS_SYSTEM_TERMINATED, 0, 0) == 1) break; } CloseHandle(hEvent); CloseHandle(hMainThread); }
HRESULT RequestTransfer(TShellExt *Self, int idxCmd) { // get the contact information MENUITEMINFOA mii = { 0 }; mii.cbSize = sizeof(mii); mii.fMask = MIIM_ID | MIIM_DATA; if ( !GetMenuItemInfoA(Self->hRootMenu, Self->idCmdFirst + idxCmd, false, &mii)) return E_INVALIDARG; // get the pointer TMenuDrawInfo *psd = (TMenuDrawInfo*)mii.dwItemData; // the ID stored in the item pointer and the ID for the menu must match if (psd == NULL || psd->wID != mii.wID) return E_INVALIDARG; // is there an IDataObject instance? HRESULT hr = E_INVALIDARG; if (Self->pDataObject != NULL) { // OpenEvent() the work object to see if the instance is still around char szBuf[100]; HANDLE hTransfer = OpenEventA(EVENT_ALL_ACCESS, false, CreateProcessUID(psd->pid, szBuf, sizeof(szBuf))); if (hTransfer != 0) { // map the ipc file again HANDLE hMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, IPC_PACKET_SIZE, IPC_PACKET_NAME); if (hMap != 0 && GetLastError() != ERROR_ALREADY_EXISTS) { // map it to process THeaderIPC *pipch = (THeaderIPC*)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); if (pipch != NULL) { // create the name of the object to be signalled by the ST lstrcpyA(pipch->SignalEventName, CreateUID(szBuf, sizeof(szBuf))); // create it HANDLE hReply = CreateEventA(NULL, false, false, pipch->SignalEventName); if (hReply != 0) { if (psd->fTypes & dtCommand) { if (psd->MenuCommandCallback) hr = psd->MenuCommandCallback(pipch, hTransfer, hReply); } else { // prepare the buffer ipcPrepareRequests(IPC_PACKET_SIZE, pipch, REQUEST_XFRFILES); // get all the files into the packet if (ipcGetFiles(pipch, Self->pDataObject, psd->hContact) == S_OK) { // need to wait for the ST to open the mapping object // since if we close it before it's opened it the data it // has will be undefined int replyBits = ipcSendRequest(hTransfer, hReply, pipch, 200); if (replyBits != REPLY_FAIL) // they got the files! hr = S_OK; } } // close the work object name CloseHandle(hReply); } // unmap it from this process UnmapViewOfFile(pipch); } // close the map CloseHandle(hMap); } // close the handle to the ST object name CloseHandle(hTransfer); } } return hr; }