From 2c73bb570b16ed862a3e28e263198273d4591074 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Fri, 30 Aug 2013 18:38:04 +0000 Subject: COM-related code rearranged git-svn-id: http://svn.miranda-ng.org/main/trunk@5889 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/ShellExt/shellext_10.vcxproj | 2 + plugins/ShellExt/shellext_10.vcxproj.filters | 6 + plugins/ShellExt/shellext_11.vcxproj | 2 + plugins/ShellExt/shellext_11.vcxproj.filters | 6 + plugins/ShellExt/src/main.cpp | 41 + plugins/ShellExt/src/shlcom.cpp | 1060 +------------------------- plugins/ShellExt/src/shlcom.h | 25 +- plugins/ShellExt/src/stdafx.h | 6 + 8 files changed, 88 insertions(+), 1060 deletions(-) (limited to 'plugins/ShellExt') diff --git a/plugins/ShellExt/shellext_10.vcxproj b/plugins/ShellExt/shellext_10.vcxproj index 45cfcfa71c..74339bf1ab 100644 --- a/plugins/ShellExt/shellext_10.vcxproj +++ b/plugins/ShellExt/shellext_10.vcxproj @@ -201,6 +201,8 @@ + + diff --git a/plugins/ShellExt/shellext_10.vcxproj.filters b/plugins/ShellExt/shellext_10.vcxproj.filters index 0e637ca837..e2d1e58a0c 100644 --- a/plugins/ShellExt/shellext_10.vcxproj.filters +++ b/plugins/ShellExt/shellext_10.vcxproj.filters @@ -61,5 +61,11 @@ Source Files + + Source Files + + + Source Files + \ No newline at end of file diff --git a/plugins/ShellExt/shellext_11.vcxproj b/plugins/ShellExt/shellext_11.vcxproj index d32623c2d2..7251574c52 100644 --- a/plugins/ShellExt/shellext_11.vcxproj +++ b/plugins/ShellExt/shellext_11.vcxproj @@ -204,6 +204,8 @@ + + diff --git a/plugins/ShellExt/shellext_11.vcxproj.filters b/plugins/ShellExt/shellext_11.vcxproj.filters index 0e637ca837..e2d1e58a0c 100644 --- a/plugins/ShellExt/shellext_11.vcxproj.filters +++ b/plugins/ShellExt/shellext_11.vcxproj.filters @@ -61,5 +61,11 @@ Source Files + + Source Files + + + Source Files + \ No newline at end of file diff --git a/plugins/ShellExt/src/main.cpp b/plugins/ShellExt/src/main.cpp index 33d1ed0b83..e7a80c94a1 100644 --- a/plugins/ShellExt/src/main.cpp +++ b/plugins/ShellExt/src/main.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "shlcom.h" HINSTANCE hInst; int hLangpack; @@ -27,6 +28,9 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) hInst = hinstDLL; DisableThreadLibraryCalls(hinstDLL); + + extern bool VistaOrLater; + VistaOrLater = GetProcAddress( GetModuleHandleA("kernel32.dll"), "GetProductInfo") != NULL; } return TRUE; @@ -37,6 +41,43 @@ extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD miranda return &pluginInfoEx; } +///////////////////////////////////////////////////////////////////////////////////////// +// exported functions + +const IID CLSID_ISHLCOM = { 0x72013A26, 0xA94C, 0x11d6, {0x85, 0x40, 0xA5, 0xE6, 0x29, 0x32, 0x71, 0x1D }}; + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + if (rclsid == CLSID_ISHLCOM) { + TClassFactoryRec *p = new TClassFactoryRec(); + HRESULT hr = p->QueryInterface(riid, ppv); + if ( FAILED(hr)) { + delete p; + return hr; + } + logA("DllGetClassObject succeeded\n"); + return S_OK; + } + + #ifdef LOG_ENABLED + RPC_CSTR szGuid; + UuidToStringA(&riid, &szGuid); + logA("DllGetClassObject {%08x-%04x-%04x-%08x%08x} failed\n", szGuid); + RpcStringFreeA(&szGuid); + #endif + + *ppv = NULL; + return CLASS_E_CLASSNOTAVAILABLE; +} + +STDAPI DllCanUnloadNow() +{ + logA("DllCanUnloadNow: %d %d\n", DllFactoryCount, DllObjectCount); + if (DllFactoryCount == 0 && DllObjectCount == 0) + return S_OK; + return S_FALSE; +} + ///////////////////////////////////////////////////////////////////////////////////////// struct HRegKey diff --git a/plugins/ShellExt/src/shlcom.cpp b/plugins/ShellExt/src/shlcom.cpp index 2b498f08e8..51d92832e0 100644 --- a/plugins/ShellExt/src/shlcom.cpp +++ b/plugins/ShellExt/src/shlcom.cpp @@ -4,22 +4,9 @@ #pragma comment(lib, "rpcrt4.lib") -static bool VistaOrLater; +bool VistaOrLater; -struct SHLCOM -{ - int FactoryCount, ObjectCount; - - SHLCOM() { - FactoryCount = ObjectCount = 0; - VistaOrLater = GetProcAddress( GetModuleHandleA("kernel32.dll"), "GetProductInfo") != NULL; - } -}; - -static SHLCOM dllobject; - -#define IPC_PACKET_SIZE (0x1000 * 32) -#define IPC_PACKET_NAME "m.mi.miranda.ipc.server" +int DllFactoryCount, DllObjectCount; struct TCMInvokeCommandInfo { @@ -59,1024 +46,14 @@ int IsCOMRegistered() ///////////////////////////////////////////////////////////////////////////////////////// -static char* CreateProcessUID(int pid, char *buf, size_t bufLen) +char* CreateProcessUID(int pid, char *buf, size_t bufLen) { sprintf_s(buf, bufLen, "mim.shlext.%d$", pid); return buf; } -static char* CreateUID(char *buf, size_t bufLen) -{ - sprintf_s(buf, bufLen, "'mim.shlext.caller%d$%d", GetCurrentProcessId(), GetCurrentThreadId()); - return buf; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void FreeGroupTreeAndEmptyGroups(HMENU hParentMenu, TGroupNode *pp, TGroupNode *p) -{ - while (p != NULL) { - TGroupNode *q = p->Right; - if (p->Left != NULL) - FreeGroupTreeAndEmptyGroups(p->Left->hMenu, p, p->Left); - - if (p->dwItems == 0) { - if (pp != NULL) - DeleteMenu(pp->hMenu, p->hMenuGroupID, MF_BYCOMMAND); - else - DeleteMenu(hParentMenu, p->hMenuGroupID, MF_BYCOMMAND); - } - else - // make sure this node's parent know's it exists - if (pp != NULL) - pp->dwItems++; - - free(p); - p = q; - } -} - -void DecideMenuItemInfo(TSlotIPC *pct, TGroupNode *pg, MENUITEMINFOA &mii, TEnumData *lParam) -{ - mii.wID = lParam->idCmdFirst; - lParam->idCmdFirst++; - // get the heap object - HANDLE hDllHeap = lParam->Self->hDllHeap; - TMenuDrawInfo *psd = (TMenuDrawInfo*)HeapAlloc(hDllHeap, 0, sizeof(TMenuDrawInfo)); - if (pct != NULL) { - psd->cch = pct->cbStrSection - 1; // no null; - psd->szText = (char*)HeapAlloc(hDllHeap, 0, pct->cbStrSection); - lstrcpyA(psd->szText, (char*)pct + sizeof(TSlotIPC)); - psd->hContact = pct->hContact; - psd->fTypes = dtContact; - // find the protocol icon array to use && which status - UINT c = lParam->Self->ProtoIconsCount; - TSlotProtoIcons *pp = lParam->Self->ProtoIcons; - psd->hStatusIcon = 0; - while (c > 0) { - c--; - if (pp[c].hProto == pct->hProto && pp[c].pid == lParam->pid) { - psd->hStatusIcon = pp[c].hIcons[pct->Status - ID_STATUS_OFFLINE]; - psd->hStatusBitmap = pp[c].hBitmaps[pct->Status - ID_STATUS_OFFLINE]; - break; - } - } // while - psd->pid = lParam->pid; - } - else if (pg != NULL) { - // store the given ID - pg->hMenuGroupID = mii.wID; - // steal the pointer from the group node it should be on the heap - psd->cch = pg->cchGroup; - psd->szText = pg->szGroup; - psd->fTypes = dtGroup; - } // if - psd->wID = mii.wID; - psd->szProfile = NULL; - // store - mii.dwItemData = UINT_PTR(psd); - - if (lParam->bOwnerDrawSupported && lParam->bShouldOwnerDraw) { - mii.fType = MFT_OWNERDRAW; - mii.dwTypeData = (LPSTR)psd; - } - else { - // normal menu - mii.fType = MFT_STRING; - if (pct != NULL) - mii.dwTypeData = LPSTR(pct) + sizeof(TSlotIPC); - else - mii.dwTypeData = pg->szGroup; - - // For Vista + let the system draw the theme && icons, pct = contact associated data - if (VistaOrLater && pct != NULL && psd != NULL) { - mii.fMask = MIIM_BITMAP | MIIM_FTYPE | MIIM_ID | MIIM_DATA | MIIM_STRING; - // BuildSkinIcons() built an array of bitmaps which we can use here - mii.hbmpItem = psd->hStatusBitmap; - } - } // if -} - -// must be called after DecideMenuItemInfo() -void BuildMRU(TSlotIPC *pct, MENUITEMINFOA &mii, TEnumData *lParam) -{ - if (pct->MRU > 0) { - lParam->Self->RecentCount++; - // lParam->Self == pointer to object data - InsertMenuItemA(lParam->Self->hRecentMenu, 0xFFFFFFFF, true, &mii); - } -} - -void BuildContactTree(TGroupNode *group, TEnumData *lParam) -{ - // set up the menu item - MENUITEMINFOA mii = { sizeof(mii) }; - mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_DATA; - - // go thru all the contacts - TSlotIPC *pct = lParam->ipch->ContactsBegin; - while (pct != NULL && pct->cbSize == sizeof(TSlotIPC) && pct->fType == REQUEST_CONTACTS) { - if (pct->hGroup != 0) { - // at the } of the slot header is the contact's display name - // && after a double NULL char there is the group string, which has the full path of the group - // this must be tokenised at '\' and we must walk the in memory group tree til we find our group - // this is faster than the old version since we only ever walk one or at most two levels of the tree - // per tokenised section, and it doesn't matter if two levels use the same group name (which is valid) - // as the tokens processed is equatable to depth of the tree - - char *sz = strtok(LPSTR(UINT_PTR(pct) + sizeof(TSlotIPC) + UINT_PTR(pct->cbStrSection) + 1), "\\"); - // restore the root - TGroupNode *pg = group; - unsigned Depth = 0; - while (sz != NULL) { - UINT Hash = murmur_hash(sz); - // find this node within - while (pg != NULL) { - // does this node have the right hash and the right depth? - if (Hash == pg->Hash && Depth == pg->Depth) - break; - // each node may have a left pointer going to a sub tree - // the path syntax doesn't know if a group is a group at the same level - // or a nested one, which means the search node can be anywhere - TGroupNode *px = pg->Left; - if (px != NULL) { - // keep searching this level - while (px != NULL) { - if (Hash == px->Hash && Depth == px->Depth) { - // found the node we're looking for at the next level to pg, px is now pq for next time - pg = px; - goto grouploop; - } - px = px->Right; - } - } - pg = pg->Right; - } -grouploop: - Depth++; - // process next token - sz = strtok(NULL, "\\"); - } - // tokenisation finished, if pg != NULL the group is found - if (pg != NULL) { - DecideMenuItemInfo(pct, NULL, mii, lParam); - BuildMRU(pct, mii, lParam); - InsertMenuItemA(pg->hMenu, 0xFFFFFFFF, true, &mii); - pg->dwItems++; - } - } - pct = pct->Next; - } -} - -void BuildMenuGroupTree(TGroupNode *p, TEnumData *lParam, HMENU hLastMenu) -{ - MENUITEMINFOA mii; - mii.cbSize = sizeof(MENUITEMINFO); - mii.fMask = MIIM_ID | MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU; - - // go thru each group and create a menu for it adding submenus too. - while (p != NULL) { - mii.hSubMenu = CreatePopupMenu(); - if (p->Left != NULL) - BuildMenuGroupTree(p->Left, lParam, mii.hSubMenu); - p->hMenu = mii.hSubMenu; - DecideMenuItemInfo(NULL, p, mii, lParam); - InsertMenuItemA(hLastMenu, 0xFFFFFFFF, true, &mii); - p = p->Right; - } -} - -// this callback is triggered by the menu code and IPC is already taking place, -// just the transfer type+data needs to be setup - -int __stdcall ClearMRUIPC( - THeaderIPC *pipch, // IPC header info, already mapped - HANDLE hWorkThreadEvent, // event object being waited on on miranda thread - HANDLE hAckEvent, // ack event object that has been created - TMenuDrawInfo *psd) // command/draw info -{ - ipcPrepareRequests(IPC_PACKET_SIZE, pipch, REQUEST_CLEARMRU); - ipcSendRequest(hWorkThreadEvent, hAckEvent, pipch, 100); - return S_OK; -} - -void RemoveCheckmarkSpace(HMENU HMENU) -{ - if (!VistaOrLater) - return; - - MENUINFO mi; - mi.cbSize = sizeof(mi); - mi.fMask = MIM_STYLE; - mi.dwStyle = MNS_CHECKORBMP; - SetMenuInfo(HMENU, &mi); -} - -void BuildMenus(TEnumData *lParam) -{ - HMENU hGroupMenu; - LPSTR Token; - TMenuDrawInfo *psd; - UINT c; - TSlotProtoIcons *pp; - - MENUITEMINFOA mii = { 0 }; - HANDLE hDllHeap = lParam->Self->hDllHeap; - HMENU hBaseMenu = lParam->Self->hRootMenu; - - // build an in memory tree of the groups - TGroupNodeList j = { 0, 0 }; - TSlotIPC *pg = lParam->ipch->GroupsBegin; - while (pg != NULL) { - if (pg->cbSize != sizeof(TSlotIPC) || pg->fType != REQUEST_GROUPS) - break; - - UINT Depth = 0; - TGroupNode *p = j.First; // start at root again - // get the group - Token = strtok(LPSTR(pg) + sizeof(TSlotIPC), "\\"); - while (Token != NULL) { - UINT Hash = murmur_hash(Token); - // if the (sub)group doesn't exist, create it. - TGroupNode *q = FindGroupNode(p, Hash, Depth); - if (q == NULL) { - q = AllocGroupNode(&j, p, Depth); - q->Depth = Depth; - // this is the hash of this group node, but it can be anywhere - // i.e. Foo\Foo this is because each node has a different depth - // trouble is contacts don't come with depths! - q->Hash = Hash; - // don't assume that pg->hGroup's hash is valid for this token - // since it maybe Miranda\Blah\Blah and we have created the first node - // which maybe Miranda, thus giving the wrong hash - // since "Miranda" can be a group of it's own and a full path - q->cchGroup = lstrlenA(Token); - q->szGroup = (LPSTR)HeapAlloc(hDllHeap, 0, q->cchGroup + 1); - lstrcpyA(q->szGroup, Token); - q->dwItems = 0; - } - p = q; - Depth++; - Token = strtok(NULL, "\\"); - } - pg = pg->Next; - } - - // build the menus inserting into hGroupMenu which will be a submenu of - // the instance menu item. e.g. Miranda -> [Groups ->] contacts - hGroupMenu = CreatePopupMenu(); - - // allocate MRU menu, this will be associated with the higher up menu - // so doesn't need to be freed (unless theres no MRUs items attached) - // This menu is per process but the handle is stored globally (like a stack) - lParam->Self->hRecentMenu = CreatePopupMenu(); - lParam->Self->RecentCount = 0; - // create group menus only if they exist! - if (lParam->ipch->GroupsBegin != NULL) { - BuildMenuGroupTree(j.First, lParam, hGroupMenu); - // add contacts that have a group somewhere - BuildContactTree(j.First, lParam); - } - - mii.cbSize = sizeof(MENUITEMINFO); - mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_DATA; - // add all the contacts that have no group (which maybe all of them) - pg = lParam->ipch->ContactsBegin; - while (pg != NULL) { - if (pg->cbSize != sizeof(TSlotIPC) || pg->fType != REQUEST_CONTACTS) - break; - if (pg->hGroup == 0) { - DecideMenuItemInfo(pg, NULL, mii, lParam); - BuildMRU(pg, mii, lParam); - InsertMenuItemA(hGroupMenu, 0xFFFFFFFF, true, &mii); - } - pg = pg->Next; - } - - // insert MRU menu as a submenu of the contact menu only if - // the MRU list has been created, the menu popup will be deleted by itself - if (lParam->Self->RecentCount > 0) { - // insert seperator and 'clear list' menu - mii.fType = MFT_SEPARATOR; - mii.fMask = MIIM_TYPE; - InsertMenuItemA(lParam->Self->hRecentMenu, 0xFFFFFFFF, true, &mii); - - // insert 'clear MRU' item and setup callback - mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_DATA; - mii.wID = lParam->idCmdFirst; - lParam->idCmdFirst++; - mii.fType = MFT_STRING; - mii.dwTypeData = lParam->ipch->ClearEntries; // "Clear entries" - // allocate menu substructure - psd = (TMenuDrawInfo*)HeapAlloc(hDllHeap, 0, sizeof(TMenuDrawInfo)); - psd->fTypes = dtCommand; - psd->MenuCommandCallback = &ClearMRUIPC; - psd->wID = mii.wID; - // this is needed because there is a clear list command per each process. - psd->pid = lParam->pid; - mii.dwItemData = (LPARAM)psd; - InsertMenuItemA(lParam->Self->hRecentMenu, 0xFFFFFFFF, true, &mii); - - // insert MRU submenu into group menu (with) ownerdraw support as needed - psd = (TMenuDrawInfo*)HeapAlloc(hDllHeap, 0, sizeof(TMenuDrawInfo)); - psd->szProfile = "MRU"; - psd->fTypes = dtGroup; - // the IPC string pointer wont be around forever, must make a copy - psd->cch = (int)strlen(lParam->ipch->MRUMenuName); - psd->szText = (LPSTR)HeapAlloc(hDllHeap, 0, psd->cch + 1); - lstrcpynA(psd->szText, lParam->ipch->MRUMenuName, sizeof(lParam->ipch->MRUMenuName) - 1); - - mii.dwItemData = (LPARAM)psd; - if (lParam->bOwnerDrawSupported && lParam->bShouldOwnerDraw) { - mii.fType = MFT_OWNERDRAW; - mii.dwTypeData = (LPSTR)psd; - } - else mii.dwTypeData = lParam->ipch->MRUMenuName; // 'Recent'; - - mii.wID = lParam->idCmdFirst; - lParam->idCmdFirst++; - mii.fMask = MIIM_TYPE | MIIM_SUBMENU | MIIM_DATA | MIIM_ID; - mii.hSubMenu = lParam->Self->hRecentMenu; - InsertMenuItemA(hGroupMenu, 0, true, &mii); - } - else { - // no items were attached to the MRU, delete the MRU menu - DestroyMenu(lParam->Self->hRecentMenu); - lParam->Self->hRecentMenu = 0; - } - - // allocate display info/memory for "Miranda" string - - mii.cbSize = sizeof(MENUITEMINFO); - if (VistaOrLater) - mii.fMask = MIIM_ID | MIIM_DATA | MIIM_FTYPE | MIIM_SUBMENU | MIIM_STRING | MIIM_BITMAP; - else - mii.fMask = MIIM_ID | MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU; - - mii.hSubMenu = hGroupMenu; - - // by default, the menu will have space for icons and checkmarks (on Vista+) && we don't need this - RemoveCheckmarkSpace(hGroupMenu); - - psd = (TMenuDrawInfo*)HeapAlloc(hDllHeap, 0, sizeof(TMenuDrawInfo)); - psd->cch = (int)strlen(lParam->ipch->MirandaName); - psd->szText = (LPSTR)HeapAlloc(hDllHeap, 0, psd->cch + 1); - lstrcpynA(psd->szText, lParam->ipch->MirandaName, sizeof(lParam->ipch->MirandaName) - 1); - // there may not be a profile name - pg = lParam->ipch->DataPtr; - psd->szProfile = NULL; - if (pg != NULL && pg->Status == STATUS_PROFILENAME) { - psd->szProfile = (LPSTR)HeapAlloc(hDllHeap, 0, pg->cbStrSection); - lstrcpyA(psd->szProfile, LPSTR(UINT_PTR(pg) + sizeof(TSlotIPC))); - } - - // owner draw menus need ID's - mii.wID = lParam->idCmdFirst; - lParam->idCmdFirst++; - psd->fTypes = dtEntry; - psd->wID = mii.wID; - psd->hContact = 0; - - // get Miranda's icon or bitmap - c = lParam->Self->ProtoIconsCount; - pp = lParam->Self->ProtoIcons; - while (c > 0) { - c--; - if (pp[c].pid == lParam->pid && pp[c].hProto == 0) { - // either of these can be 0 - psd->hStatusIcon = pp[c].hIcons[0]; - mii.hbmpItem = pp[c].hBitmaps[0]; - break; - } - } - mii.dwItemData = (UINT_PTR)psd; - if (lParam->bOwnerDrawSupported && lParam->bShouldOwnerDraw) { - mii.fType = MFT_OWNERDRAW; - mii.dwTypeData = (LPSTR)psd; - } - else { - mii.fType = MFT_STRING; - mii.dwTypeData = lParam->ipch->MirandaName; - mii.cch = sizeof(lParam->ipch->MirandaName) - 1; - } - // add it all - InsertMenuItemA(hBaseMenu, 0, true, &mii); - // free the group tree - FreeGroupTreeAndEmptyGroups(hGroupMenu, NULL, j.First); -} - -void BuildSkinIcons(TEnumData *lParam) -{ - IWICImagingFactory *factory = (VistaOrLater) ? ARGB_GetWorker() : NULL; - - TSlotIPC *pct = lParam->ipch->NewIconsBegin; - TShlComRec *Self = lParam->Self; - while (pct != NULL) { - if (pct->cbSize != sizeof(TSlotIPC) || pct->fType != REQUEST_NEWICONS) - break; - - TSlotProtoIcons *p = (TSlotProtoIcons*)(PBYTE(pct) + sizeof(TSlotIPC)); - Self->ProtoIcons = (TSlotProtoIcons*)realloc(Self->ProtoIcons, (Self->ProtoIconsCount + 1) * sizeof(TSlotProtoIcons)); - TSlotProtoIcons *d = &Self->ProtoIcons[Self->ProtoIconsCount]; - memmove(d, p, sizeof(TSlotProtoIcons)); - - // if using Vista (or later), clone all the icons into bitmaps and keep these around, - // if using anything older, just use the default code, the bitmaps (and/or icons) will be freed - // with the shell object. - - for (int j = 0; j < 10; j++) { - if (VistaOrLater) { - d->hBitmaps[j] = ARGB_BitmapFromIcon(factory, Self->hMemDC, p->hIcons[j]); - d->hIcons[j] = NULL; - } - else { - d->hBitmaps[j] = NULL; - d->hIcons[j] = CopyIcon(p->hIcons[j]); - } - } - - Self->ProtoIconsCount++; - pct = pct->Next; - } - - if (factory) - factory->Release(); -} - -BOOL __stdcall ProcessRequest(HWND hwnd, LPARAM param) -{ - HANDLE hMirandaWorkEvent; - int replyBits; - 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. - 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 - 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(false, 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; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -TShlComRec::TShlComRec() -{ - RefCount = 1; - hDllHeap = HeapCreate(0, 0, 0); - hRootMenu = 0; - hRecentMenu = 0; - RecentCount = 0; - idCmdFirst = 0; - pDataObject = NULL; - ProtoIcons = NULL; - ProtoIconsCount = 0; - // create an inmemory DC - HDC DC = GetDC(0); - hMemDC = CreateCompatibleDC(DC); - ReleaseDC(0, DC); - // keep count on the number of objects - dllobject.ObjectCount++; -} - -HRESULT TShlComRec::QueryInterface(REFIID riid, void **ppvObject) -{ - // IShellExtInit is given when the TShlRec is created - if (riid == IID_IContextMenu || riid == IID_IContextMenu2 || riid == IID_IContextMenu3) { - *ppvObject = (IContextMenu3*)this; - RefCount++; - logA("TShlComRec[%p] retrieved as IContextMenu3: %d\n", this, RefCount); - return S_OK; - } - - // under XP, it may ask for IShellExtInit again, this fixes the -double- click to see menus issue - // which was really just the object not being created - if (riid == IID_IShellExtInit) { - *ppvObject = (IShellExtInit*)this; - RefCount++; - logA("TShlComRec[%p] retrieved as IContextMenu3: %d\n", this, RefCount); - return S_OK; - } - - // and, finally, IUnknown - if (riid == IID_IUnknown) { - *ppvObject = this; - RefCount++; - logA("TShlComRec[%p] retrieved as IUnknown: %d\n", this, RefCount); - return S_OK; - } - - *ppvObject = NULL; - #ifdef LOG_ENABLED - RPC_CSTR szGuid; - UuidToStringA(&riid, &szGuid); - logA("TShlComRec[%p] failed as {%s}\n", this, szGuid); - RpcStringFreeA(&szGuid); - #endif - return E_NOINTERFACE; -} - -ULONG TShlComRec::AddRef() -{ - RefCount++; - logA("TShlComRec[%p] added ref: %d\n", this, RefCount); - return RefCount; -} - -ULONG TShlComRec::Release() -{ - ULONG ret = --RefCount; - if (RefCount == 0) { - // time to go byebye. - // Note MRU menu is associated with a window (indirectly) so windows will free it. - // free icons! - if (ProtoIcons != NULL) { - ULONG c = ProtoIconsCount; - while (c > 0) { - c--; - TSlotProtoIcons *p = &ProtoIcons[c]; - for (int j = 0; j < 10; j++) { - if (p->hIcons[j] != 0) - DestroyIcon(p->hIcons[j]); - if (p->hBitmaps[j] != 0) - DeleteObject(p->hBitmaps[j]); - } - } - free(ProtoIcons); - ProtoIcons = NULL; - } - // free IDataObject reference if pointer exists - if (pDataObject != NULL) { - pDataObject->Release(); - pDataObject = NULL; - } - // free the heap and any memory allocated on it - HeapDestroy(hDllHeap); - // destroy the DC - if (hMemDC != 0) - DeleteDC(hMemDC); - - // free the instance (class record) created - logA("TShlComRec[%p] final release\n", this); - delete this; - dllobject.ObjectCount--; - } - else logA("TShlComRec[%p] release ref: %d\n", this, RefCount); - - return ret; -} - -HRESULT TShlComRec::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID) -{ - // DObj is a pointer to an instance of IDataObject which is a pointer itself - // it contains a pointer to a function table containing the function pointer - // address of GetData() - the instance data has to be passed explicitly since - // all compiler magic has gone. - if (pdtobj == NULL) - return E_INVALIDARG; - - // if an instance already exists, free it. - if (pDataObject != NULL) - pDataObject->Release(); - - // store the new one and AddRef() it - pDataObject = pdtobj; - pDataObject->AddRef(); - return S_OK; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct DllVersionInfo -{ - DWORD cbSize; - DWORD dwMajorVersion, dwMinorVersion, dwBuildNumber, dwPlatformID; -}; - -typedef HRESULT (__stdcall *pfnDllGetVersion)(DllVersionInfo*); - -HRESULT TShlComRec::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT _idCmdFirst, UINT _idCmdLast, UINT uFlags) -{ - if (((LOWORD(uFlags) & CMF_VERBSONLY) != CMF_VERBSONLY) && ((LOWORD(uFlags) & CMF_DEFAULTONLY) != CMF_DEFAULTONLY)) { - bool bMF_OWNERDRAW = false; - // get the shell version - pfnDllGetVersion DllGetVersionProc = (pfnDllGetVersion)GetProcAddress( GetModuleHandleA("shell32.dll"), "DllGetVersion"); - if (DllGetVersionProc != NULL) { - DllVersionInfo dvi; - dvi.cbSize = sizeof(dvi); - if (DllGetVersionProc(&dvi) >= 0) - // it's at least 4.00 - bMF_OWNERDRAW = (dvi.dwMajorVersion > 4) || (dvi.dwMinorVersion >= 71); - } - - // if we're using Vista (or later), the ownerdraw code will be disabled, because the system draws the icons. - if (VistaOrLater) - bMF_OWNERDRAW = false; - - HANDLE hMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, IPC_PACKET_SIZE, IPC_PACKET_NAME); - if (hMap != 0 && GetLastError() != ERROR_ALREADY_EXISTS) { - TEnumData ed; - // map the memory to this address space - THeaderIPC *pipch = (THeaderIPC*)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); - if (pipch != NULL) { - // let the callback have instance vars - ed.Self = this; - // not used 'ere - hRootMenu = hmenu; - // store the first ID to offset with index for InvokeCommand() - idCmdFirst = _idCmdFirst; - // store the starting index to offset - ed.bOwnerDrawSupported = bMF_OWNERDRAW; - ed.bShouldOwnerDraw = true; - ed.idCmdFirst = idCmdFirst; - ed.ipch = pipch; - // allocate a wait object so the ST can signal us, it can't be anon - // since it has to used by OpenEvent() - CreateUID(pipch->SignalEventName, sizeof(pipch->SignalEventName)); - // create the wait wait-for-wait object - ed.hWaitFor = CreateEventA(NULL, false, false, pipch->SignalEventName); - if (ed.hWaitFor != 0) { - // enumerate all the top level windows to find all loaded MIRANDACLASS classes - EnumWindows(&ProcessRequest, LPARAM(&ed)); - // close the wait-for-reply object - CloseHandle(ed.hWaitFor); - } - // unmap the memory from this address space - UnmapViewOfFile(pipch); - } - // close the mapping - CloseHandle(hMap); - // use the MSDN recommended way, thou there ain't much difference - return MAKE_HRESULT(0, 0, (ed.idCmdFirst - _idCmdFirst) + 1); - } - } - - // same as giving a SEVERITY_SUCCESS, FACILITY_NULL, since that - // just clears the higher bits, which is done anyway - return MAKE_HRESULT(0, 0, 1); -} - -HRESULT TShlComRec::GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pReserved, LPSTR pszName, UINT cchMax) -{ - return E_NOTIMPL; -} - -HRESULT ipcGetFiles(THeaderIPC *pipch, IDataObject* pDataObject, HANDLE hContact) -{ - FORMATETC fet; - fet.cfFormat = CF_HDROP; - fet.ptd = NULL; - fet.dwAspect = DVASPECT_CONTENT; - fet.lindex = -1; - fet.tymed = TYMED_HGLOBAL; - - STGMEDIUM stgm; - HRESULT hr = pDataObject->GetData(&fet, &stgm); - if (hr == S_OK) { - // FIX, actually lock the global object and get a pointer - HANDLE hDrop = GlobalLock(stgm.hGlobal); - if (hDrop != 0) { - // get the maximum number of files - UINT iFile, iFileMax = DragQueryFileA((HDROP)stgm.hGlobal, -1, NULL, 0); - for (iFile = 0; iFile < iFileMax; iFile++) { - // get the size of the file path - int cbSize = DragQueryFileA((HDROP)stgm.hGlobal, iFile, NULL, 0); - // get the buffer - TSlotIPC *pct = ipcAlloc(pipch, cbSize + 1); // including null term - // allocated? - if (pct == NULL) - break; - // store the hContact - pct->hContact = hContact; - // copy it to the buffer - DragQueryFileA((HDROP)stgm.hGlobal, iFile, LPSTR(pct) + sizeof(TSlotIPC), pct->cbStrSection); - } - // store the number of files - pipch->Slots = iFile; - GlobalUnlock(stgm.hGlobal); - } // if hDrop check - // release the mediumn the lock may of failed - ReleaseStgMedium(&stgm); - } - return hr; -} - -HRESULT RequestTransfer(TShlComRec *Self, int idxCmd) -{ - // get the contact information - MENUITEMINFOA mii; - mii.cbSize = sizeof(MENUITEMINFO); - 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, psd); - } - 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; -} - -HRESULT TShlComRec::InvokeCommand(CMINVOKECOMMANDINFO *pici) -{ - return RequestTransfer(this, LOWORD(UINT_PTR(pici->lpVerb))); -} - -HRESULT TShlComRec::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult) -{ - LRESULT Dummy; - if (plResult == NULL) - plResult = &Dummy; - - SIZE tS; - HBRUSH hBr; - - *plResult = true; - if (uMsg == WM_DRAWITEM && wParam == 0) { - // either a main sub menu, a group menu or a contact - DRAWITEMSTRUCT *dwi = (DRAWITEMSTRUCT*)lParam; - TMenuDrawInfo *psd = (TMenuDrawInfo*)dwi->itemData; - // don't fill - SetBkMode(dwi->hDC, TRANSPARENT); - // where to draw the icon? - RECT icorc; - icorc.left = 0; - icorc.top = dwi->rcItem.top + ((dwi->rcItem.bottom - dwi->rcItem.top) / 2) - (16 / 2); - icorc.right = icorc.left + 16; - icorc.bottom = icorc.top + 16; - // draw for groups - if (psd->fTypes & (dtGroup | dtEntry)) { - hBr = GetSysColorBrush(COLOR_MENU); - FillRect(dwi->hDC, &dwi->rcItem, hBr); - DeleteObject(hBr); - - if (dwi->itemState & ODS_SELECTED) { - // only do this for entry menu types otherwise a black mask - // is drawn under groups - hBr = GetSysColorBrush(COLOR_HIGHLIGHT); - FillRect(dwi->hDC, &dwi->rcItem, hBr); - DeleteObject(hBr); - SetTextColor(dwi->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); - } - // draw icon - if (dwi->itemState & ODS_SELECTED) - hBr = GetSysColorBrush(COLOR_HIGHLIGHT); - else - hBr = GetSysColorBrush(COLOR_MENU); - - DrawIconEx(dwi->hDC, icorc.left + 1, icorc.top, psd->hStatusIcon, 16, 16, 0, hBr, DI_NORMAL); - DeleteObject(hBr); - - // draw the text - dwi->rcItem.left += dwi->rcItem.bottom - dwi->rcItem.top - 2; - DrawTextA(dwi->hDC, psd->szText, psd->cch, &dwi->rcItem, DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER); - // draw the name of the database text if it's there - if (psd->szProfile != NULL) { - GetTextExtentPoint32A(dwi->hDC, psd->szText, psd->cch, &tS); - dwi->rcItem.left += tS.cx + 8; - SetTextColor(dwi->hDC, GetSysColor(COLOR_GRAYTEXT)); - DrawTextA(dwi->hDC, psd->szProfile, lstrlenA(psd->szProfile), &dwi->rcItem, DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER); - } - } - else { - // it's a contact! - hBr = GetSysColorBrush(COLOR_MENU); - FillRect(dwi->hDC, &dwi->rcItem, hBr); - DeleteObject(hBr); - if (dwi->itemState & ODS_SELECTED) { - hBr = GetSysColorBrush(COLOR_HIGHLIGHT); - FillRect(dwi->hDC, &dwi->rcItem, hBr); - DeleteObject(hBr); - SetTextColor(dwi->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); - } - // draw icon - if (dwi->itemState & ODS_SELECTED) - hBr = GetSysColorBrush(COLOR_HIGHLIGHT); - else - hBr = GetSysColorBrush(COLOR_MENU); - - DrawIconEx(dwi->hDC, icorc.left + 2, icorc.top, psd->hStatusIcon, 16, 16, 0, hBr, DI_NORMAL); - DeleteObject(hBr); - - // draw the text - dwi->rcItem.left += dwi->rcItem.bottom - dwi->rcItem.top + 1; - DrawTextA(dwi->hDC, psd->szText, psd->cch, &dwi->rcItem, DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER); - } - } - else if (uMsg == WM_MEASUREITEM) { - // don't check if it's really a menu - MEASUREITEMSTRUCT *msi = (MEASUREITEMSTRUCT*)lParam; - TMenuDrawInfo *psd = (TMenuDrawInfo*)msi->itemData; - NONCLIENTMETRICS ncm; - ncm.cbSize = (VistaOrLater) ? sizeof(ncm) : offsetof(NONCLIENTMETRICS, iPaddedBorderWidth); - SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0); - // create the font used in menus, this font should be cached somewhere really - HFONT hFont = CreateFontIndirect(&ncm.lfMenuFont); - // select in the font - HFONT hOldFont = (HFONT)SelectObject(hMemDC, hFont); - // default to an icon - int dx = 16; - // get the size 'n' account for the icon - GetTextExtentPoint32A(hMemDC, psd->szText, psd->cch, &tS); - dx += tS.cx; - // main menu item? - if (psd->szProfile != NULL) { - GetTextExtentPoint32A(hMemDC, psd->szProfile, lstrlenA(psd->szProfile), &tS); - dx += tS.cx; - } - // store it - msi->itemWidth = dx + ncm.iMenuWidth; - msi->itemHeight = ncm.iMenuHeight + 2; - if (tS.cy > (int)msi->itemHeight) - msi->itemHeight += tS.cy - msi->itemHeight; - // clean up - SelectObject(hMemDC, hOldFont); - DeleteObject(hFont); - } - return S_OK; -} - -HRESULT TShlComRec::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - return HandleMenuMsg2(uMsg, wParam, lParam, NULL); -} - ///////////////////////////////////////////////////////////////////////////////////////// -struct TClassFactoryRec : public IClassFactory -{ - TClassFactoryRec() : - RefCount(1) - { - dllobject.FactoryCount++; - } - - LONG RefCount; - - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); - ULONG STDMETHODCALLTYPE AddRef(void); - ULONG STDMETHODCALLTYPE Release(void); - - HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject); - HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock); -}; - -HRESULT TClassFactoryRec::QueryInterface(REFIID riid, void **ppvObject) -{ - #ifdef LOG_ENABLED - RPC_CSTR szGuid; - UuidToStringA(&riid, &szGuid); - logA("TClassFactoryRec::QueryInterface {%08x-%04x-%04x-%08x%08x} failed\n", szGuid); - RpcStringFreeA(&szGuid); - #endif - *ppvObject = NULL; - return E_NOINTERFACE; -} - -ULONG TClassFactoryRec::AddRef() -{ - return ++RefCount; -} - -ULONG TClassFactoryRec::Release() -{ - ULONG result = --RefCount; - if (result == 0) { - logA("TClassFactoryRec released\n"); - delete this; - dllobject.FactoryCount--; - } - return result; -} - -HRESULT TClassFactoryRec::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject) -{ - *ppvObject = NULL; - - if (pUnkOuter != NULL) - return CLASS_E_NOAGGREGATION; - - // Before Vista, the system queried for a IShell interface queried for a context menu, Vista now - // queries for a context menu (or a shell menu) QI()'s the other interface - if (riid == IID_IContextMenu) { - TShlComRec *p = new TShlComRec(); - *ppvObject = (IContextMenu3*)p; - logA("TClassFactoryRec created as IContextMenu3: %p\n", p); - return S_OK; - } - if (riid == IID_IShellExtInit) { - TShlComRec *p = new TShlComRec(); - *ppvObject = (IShellExtInit*)p; - logA("TClassFactoryRec created as IShellExtInit: %p\n", p); - return S_OK; - } - - return E_NOTIMPL; -} - -HRESULT TClassFactoryRec::LockServer(BOOL) -{ - return E_NOTIMPL; -} - // // IPC part // @@ -1541,37 +518,6 @@ void InvokeThreadServer() mir_forkthread(&ThreadServer, hMainThread); } -// exported functions - -const IID CLSID_ISHLCOM = { 0x72013A26, 0xA94C, 0x11d6, {0x85, 0x40, 0xA5, 0xE6, 0x29, 0x32, 0x71, 0x1D }}; - -STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) -{ - if (rclsid == CLSID_ISHLCOM && riid == IID_IClassFactory && FindWindowA(MIRANDACLASS, NULL) != 0) { - *ppv = new TClassFactoryRec(); - logA("DllGetClassObject succeeded\n"); - return S_OK; - } - - #ifdef LOG_ENABLED - RPC_CSTR szGuid; - UuidToStringA(&riid, &szGuid); - logA("DllGetClassObject {%08x-%04x-%04x-%08x%08x} failed\n", szGuid); - RpcStringFreeA(&szGuid); - #endif - - *ppv = NULL; - return CLASS_E_CLASSNOTAVAILABLE; -} - -STDAPI DllCanUnloadNow() -{ - logA("DllCanUnloadNow: %d %d\n", dllobject.FactoryCount, dllobject.ObjectCount); - if (dllobject.FactoryCount == 0 && dllobject.ObjectCount == 0) - return S_OK; - return S_FALSE; -} - // helper functions HRESULT RemoveCOMRegistryEntries() diff --git a/plugins/ShellExt/src/shlcom.h b/plugins/ShellExt/src/shlcom.h index ab0f337fe7..c4b24ac6fd 100644 --- a/plugins/ShellExt/src/shlcom.h +++ b/plugins/ShellExt/src/shlcom.h @@ -40,6 +40,9 @@ #define HIPC_NOICONS 1 +#define IPC_PACKET_SIZE (0x1000 * 32) +#define IPC_PACKET_NAME "m.mi.miranda.ipc.server" + ///////////////////////////////////////////////////////////////////////////////////////// struct TGroupNode @@ -114,9 +117,9 @@ struct THeaderIPC ///////////////////////////////////////////////////////////////////////////////////////// -struct TShlComRec : public IShellExtInit, public IContextMenu3 +struct TShellExt : public IShellExtInit, public IContextMenu3, public MZeroedObject { - TShlComRec(); + TShellExt(); ULONG RefCount; // this is owned by the shell after items are added 'n' is used to @@ -158,7 +161,7 @@ struct TShlComRec : public IShellExtInit, public IContextMenu3 struct TEnumData { - TShlComRec *Self; + TShellExt *Self; // autodetected, don't hard code since shells that don't support it // won't send WM_MEASUREITETM/WM_DRAWITEM at all. @@ -172,6 +175,20 @@ struct TEnumData DWORD pid; // sub-unique value used to make work object name }; +struct TClassFactoryRec : public IClassFactory +{ + TClassFactoryRec(); + + LONG RefCount; + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(void); + ULONG STDMETHODCALLTYPE Release(void); + + HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject); + HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock); +}; + ///////////////////////////////////////////////////////////////////////////////////////// enum TSlotDrawType {dtEntry = 0x01, dtGroup = 0x02, dtContact = 0x04, dtCommand = 0x08 }; @@ -205,3 +222,5 @@ void ipcFixupAddresses(BOOL FromServer, THeaderIPC *pipch); TGroupNode* AllocGroupNode(TGroupNodeList *list, TGroupNode *Root, int Depth); TGroupNode* FindGroupNode(TGroupNode* p, const DWORD Hash, int Depth); + +char* CreateProcessUID(int pid, char *buf, size_t bufLen); diff --git a/plugins/ShellExt/src/stdafx.h b/plugins/ShellExt/src/stdafx.h index 4527f78a08..1a0f2574f0 100644 --- a/plugins/ShellExt/src/stdafx.h +++ b/plugins/ShellExt/src/stdafx.h @@ -46,9 +46,15 @@ HRESULT RemoveCOMRegistryEntries(); extern HINSTANCE hInst; extern HANDLE hLogger; +extern int DllFactoryCount, DllObjectCount; +extern bool VistaOrLater; int OnOptionsInit(WPARAM wParam, LPARAM lParam); +#ifdef _DEBUG +#define LOG_ENABLED +#endif + #ifdef LOG_ENABLED void logA(const char *format, ...); #else -- cgit v1.2.3