From 278212c375c66cb5d4c95082f86b9014137dca19 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Sat, 24 Aug 2013 08:55:18 +0000 Subject: first version that works git-svn-id: http://svn.miranda-ng.org/main/trunk@5806 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/ShellExt/shellext_10.vcxproj | 1 + plugins/ShellExt/shellext_10.vcxproj.filters | 3 ++ plugins/ShellExt/shellext_11.vcxproj | 1 + plugins/ShellExt/shellext_11.vcxproj.filters | 3 ++ plugins/ShellExt/src/shlcom.cpp | 75 ++++++++++++++-------------- plugins/ShellExt/src/shlicons.cpp | 71 ++++++++++++++++++++++++++ plugins/ShellExt/src/shlicons.h | 21 +------- 7 files changed, 119 insertions(+), 56 deletions(-) create mode 100644 plugins/ShellExt/src/shlicons.cpp (limited to 'plugins') diff --git a/plugins/ShellExt/shellext_10.vcxproj b/plugins/ShellExt/shellext_10.vcxproj index fb5ad4ccb5..fb9612b919 100644 --- a/plugins/ShellExt/shellext_10.vcxproj +++ b/plugins/ShellExt/shellext_10.vcxproj @@ -201,6 +201,7 @@ + Create diff --git a/plugins/ShellExt/shellext_10.vcxproj.filters b/plugins/ShellExt/shellext_10.vcxproj.filters index 94085f5086..edd3cd00af 100644 --- a/plugins/ShellExt/shellext_10.vcxproj.filters +++ b/plugins/ShellExt/shellext_10.vcxproj.filters @@ -55,5 +55,8 @@ 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 8b133f32fc..a69693f4a5 100644 --- a/plugins/ShellExt/shellext_11.vcxproj +++ b/plugins/ShellExt/shellext_11.vcxproj @@ -204,6 +204,7 @@ + Create diff --git a/plugins/ShellExt/shellext_11.vcxproj.filters b/plugins/ShellExt/shellext_11.vcxproj.filters index 94085f5086..edd3cd00af 100644 --- a/plugins/ShellExt/shellext_11.vcxproj.filters +++ b/plugins/ShellExt/shellext_11.vcxproj.filters @@ -55,5 +55,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/plugins/ShellExt/src/shlcom.cpp b/plugins/ShellExt/src/shlcom.cpp index 11c6616116..d4efcd09c6 100644 --- a/plugins/ShellExt/src/shlcom.cpp +++ b/plugins/ShellExt/src/shlcom.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "shlcom.h" +#include "shlicons.h" static bool VistaOrLater; @@ -59,14 +60,14 @@ int IsCOMRegistered() static string CreateProcessUID(int pid) { char buf[100]; - mir_snprintf(buf, sizeof(buf), "mim.shlext.%d$", pid); + sprintf_s(buf, sizeof(buf), "mim.shlext.%d$", pid); return buf; } static string CreateUID() { char buf[100]; - mir_snprintf(buf, sizeof(buf), "'mim.shlext.caller%d$%d", GetCurrentProcessId(), GetCurrentThreadId()); + sprintf_s(buf, sizeof(buf), "'mim.shlext.caller%d$%d", GetCurrentProcessId(), GetCurrentThreadId()); return buf; } @@ -467,33 +468,40 @@ void BuildMenus(TEnumData *lParam) void BuildSkinIcons(TEnumData *lParam) { - TSlotIPC *pct; - TShlComRec *Self; - UINT j; + IWICImagingFactory *factory = (VistaOrLater) ? ARGB_GetWorker() : NULL; - pct = lParam->ipch->NewIconsBegin; - Self = lParam->Self; + 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*)mir_realloc(Self->ProtoIcons, (Self->ProtoIconsCount + 1) * sizeof(TSlotProtoIcons)); + 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 (| later), clone all the icons into bitmaps && keep these around, - // if using anything older, just use the default code, the bitmaps (&& | icons) will be freed + // 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 (j = 0; j < 10; j++) { - d->hBitmaps[j] = 0; - d->hIcons[j] = CopyIcon(p->hIcons[j]); + 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) @@ -513,7 +521,7 @@ BOOL __stdcall ProcessRequest(HWND hwnd, LPARAM param) hMirandaWorkEvent = OpenEventA(EVENT_ALL_ACCESS, false, CreateProcessUID(pid).c_str()); if (hMirandaWorkEvent != 0) { GetClassNameA(hwnd, szBuf, sizeof(szBuf)); - if ( lstrcmpA(szBuf, MIRANDANAME) != 0) { + if ( lstrcmpA(szBuf, MIRANDACLASS) != 0) { // opened but not valid. CloseHandle(hMirandaWorkEvent); return true; @@ -559,8 +567,6 @@ BOOL __stdcall ProcessRequest(HWND hwnd, LPARAM param) TShlComRec::TShlComRec() { - HDC DC; - RefCount = 1; hDllHeap = HeapCreate(0, 0, 0); hRootMenu = 0; @@ -571,7 +577,7 @@ TShlComRec::TShlComRec() ProtoIcons = NULL; ProtoIconsCount = 0; // create an inmemory DC - DC = GetDC(0); + HDC DC = GetDC(0); hMemDC = CreateCompatibleDC(DC); ReleaseDC(0, DC); // keep count on the number of objects @@ -624,7 +630,7 @@ ULONG TShlComRec::Release() DeleteObject(p->hBitmaps[j]); } } - mir_free(ProtoIcons); + free(ProtoIcons); ProtoIcons = NULL; } // free IDataObject reference if pointer exists @@ -679,17 +685,13 @@ HRESULT TShlComRec::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT _idCmdFir if (((LOWORD(uFlags) & CMF_VERBSONLY) != CMF_VERBSONLY) && ((LOWORD(uFlags) & CMF_DEFAULTONLY) != CMF_DEFAULTONLY)) { bool bMF_OWNERDRAW = false; // get the shell version - HINSTANCE hShellInst = LoadLibraryA("shell32.dll"); - if (hShellInst != 0) { - pfnDllGetVersion DllGetVersionProc = (pfnDllGetVersion)GetProcAddress(hShellInst, "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); - } - FreeLibrary(hShellInst); + 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 (| later), the ownerdraw code will be disabled, because the system draws the icons. @@ -719,7 +721,7 @@ HRESULT TShlComRec::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT _idCmdFir // 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 MIRANDANAME classes + // 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); @@ -1184,20 +1186,21 @@ void ipcGetSkinIcons(THeaderIPC *ipch) char szTmp[64]; int protoCount; - PROTOACCOUNT *pp; + PROTOACCOUNT **pp; if ( CallService(MS_PROTO_ENUMACCOUNTS, WPARAM(&protoCount), LPARAM(&pp)) == 0 && protoCount != 0) { spi.pid = GetCurrentProcessId(); while (protoCount > 0) { - lstrcpyA(szTmp, pp->szModuleName); + PROTOACCOUNT *pa = *pp; + lstrcpyA(szTmp, pa->szModuleName); lstrcatA(szTmp, PS_GETCAPS); DWORD dwCaps = CallService(szTmp, PFLAGNUM_1, 0); if (dwCaps && PF1_FILESEND) { TSlotIPC *pct = ipcAlloc(ipch, sizeof(TSlotProtoIcons)); if (pct != NULL) { // capture all the icons! - spi.hProto = mir_hashstr(pp->szModuleName); + spi.hProto = mir_hashstr(pa->szModuleName); for (int j = 0; j <= 10; j++) - spi.hIcons[j] = LoadSkinnedProtoIcon(pp->szModuleName, ID_STATUS_OFFLINE + j); + spi.hIcons[j] = LoadSkinnedProtoIcon(pa->szModuleName, ID_STATUS_OFFLINE + j); pct->fType = REQUEST_NEWICONS; memcpy(LPSTR(pct) + sizeof(TSlotIPC), &spi, sizeof(TSlotProtoIcons)); @@ -1510,9 +1513,7 @@ const IID CLSID_ISHLCOM = { 0x72013A26, 0xA94C, 0x11d6, {0x85, 0x40, 0xA5, 0xE6, STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) { - MessageBoxA(0, "Ding!", "Dong", MB_OK); - - if (rclsid == CLSID_ISHLCOM && riid == IID_IClassFactory && FindWindowA(MIRANDANAME, NULL) != 0) { + if (rclsid == CLSID_ISHLCOM && riid == IID_IClassFactory && FindWindowA(MIRANDACLASS, NULL) != 0) { *ppv = new TClassFactoryRec(); return S_OK; } diff --git a/plugins/ShellExt/src/shlicons.cpp b/plugins/ShellExt/src/shlicons.cpp new file mode 100644 index 0000000000..20f941a03e --- /dev/null +++ b/plugins/ShellExt/src/shlicons.cpp @@ -0,0 +1,71 @@ +#include "stdafx.h" +#include "shlicons.h" + +#pragma comment(lib, "windowscodecs.lib") +/* +The following implementation has been ported from: + +http://web.archive.org/web/20080121112802/http://shellrevealed.com/blogs/shellblog/archive/2007/02/06/Vista-Style-Menus_2C00_-Part-1-_2D00_-Adding-icons-to-standard-menus.aspx + +It uses WIC (Windows Imaging Codec) to convert the given Icon into a bitmap in ARGB format, this is required +by Windows for use as an icon (but in bitmap format), so that Windows draws everything (including theme) +so we don't have to. + +Why didn't they just do this themselves? ... +*/ + +/* + The object returned from this function has to be released using the QI COM interface, don't forget. + Note this function won't work on anything where WIC isn't installed (XP can have it installed, but not by default) + anything less won't work. +*/ + +IWICImagingFactory* ARGB_GetWorker() +{ + IWICImagingFactory *res = NULL; + CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, (void**)&res); + return res; +} + +HBITMAP ARGB_BitmapFromIcon(IWICImagingFactory *Factory, HDC hDC, HICON hIcon) +{ + HBITMAP hBmp = NULL; + + // This code gives an icon to WIC and gets a bitmap object in return, it then creates a DIB section + // which is 32bits and the same H*W as the icon. It then asks the bitmap object to copy itself into the DIB } + + BITMAPINFO bmi = { 0 }; + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biBitCount = 32; + + IWICBitmap *bitmap = NULL; + HRESULT hr = Factory->CreateBitmapFromHICON(hIcon, &bitmap); + if (hr == S_OK) { + int cx, cy; + hr = bitmap->GetSize((PUINT)&cx, (PUINT)&cy); + if (hr == S_OK) { + bmi.bmiHeader.biWidth = cx; + bmi.bmiHeader.biHeight = -cy; + + void *pbBuffer; + hBmp = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, &pbBuffer, 0, 0); + if (hBmp != 0) { + UINT cbStride = cx * sizeof(DWORD); // ARGB = DWORD + UINT cbBuffer = cy * cbStride; + // note: the pbBuffer memory is owned by the DIB and will be freed when the bitmap is released + hr = bitmap->CopyPixels(NULL, cbStride, cbBuffer, (PBYTE)pbBuffer); + if (hr != S_OK) { + // the copy failed, delete the DIB + DeleteObject(hBmp); + hBmp = NULL; + } + } + } + // release the bitmap object now + bitmap->Release(); + } + + return hBmp; +} diff --git a/plugins/ShellExt/src/shlicons.h b/plugins/ShellExt/src/shlicons.h index 8405bf69cc..6010c8c489 100644 --- a/plugins/ShellExt/src/shlicons.h +++ b/plugins/ShellExt/src/shlicons.h @@ -1,21 +1,4 @@ -struct TWICBitmap : public IWICBitmapSource -{ - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); - virtual ULONG STDMETHODCALLTYPE AddRef(void); - virtual ULONG STDMETHODCALLTYPE Release(void); +IWICImagingFactory* ARGB_GetWorker(); - virtual HRESULT STDMETHODCALLTYPE GetSize(UINT *puiWidth, UINT *puiHeight); - virtual HRESULT STDMETHODCALLTYPE GetPixelFormat(WICPixelFormatGUID *pPixelFormat); - virtual HRESULT STDMETHODCALLTYPE GetResolution(double *pDpiX, double *pDpiY); - virtual HRESULT STDMETHODCALLTYPE CopyPalette(IWICPalette *pIPalette); - virtual HRESULT STDMETHODCALLTYPE CopyPixels(const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer); -}; - -struct TImageFactory : public IImagingFactory -{ -}; - -TImageFactory* ARGB_GetWorker(); - -HBITMAP ARGB_BitmapFromIcon(TImageFactory* Factory, HDC hdc, HICON hIcon); +HBITMAP ARGB_BitmapFromIcon(IWICImagingFactory *Factory, HDC hdc, HICON hIcon); -- cgit v1.2.3