diff options
Diffstat (limited to 'plugins/ShellExt/src')
| -rw-r--r-- | plugins/ShellExt/src/main.cpp | 41 | ||||
| -rw-r--r-- | plugins/ShellExt/src/shlcom.cpp | 1060 | ||||
| -rw-r--r-- | plugins/ShellExt/src/shlcom.h | 25 | ||||
| -rw-r--r-- | plugins/ShellExt/src/stdafx.h | 6 | 
4 files changed, 72 insertions, 1060 deletions
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;
 @@ -38,6 +42,43 @@ extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD miranda  }
  /////////////////////////////////////////////////////////////////////////////////////////
 +// 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
  | 
