#include "stdafx.h" #include "shlcom.h" CMPlugin g_plugin; bool bIsVistaPlus; BOOL WINAPI DllMain(HINSTANCE hinstDLL, uint32_t fdwReason, LPVOID) { if (fdwReason == DLL_PROCESS_ATTACH) { bIsVistaPlus = GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetProductInfo") != 0; DisableThreadLibraryCalls(hinstDLL); } return TRUE; } #ifdef _WIN64 #define MIRANDA_PROCESS L"miranda64.exe" #else #define MIRANDA_PROCESS L"miranda32.exe" #endif #include #pragma comment(lib, "delayimp.lib") static bool bModuleInited = false; static wchar_t* FindSlash(wchar_t *str) { for (wchar_t *p = str + lstrlenW(str); p >= str; p--) if (*p == '\\') return p; return nullptr; } static bool GetMirandaPath(wchar_t * wszPath) { DWORD dwSize = MAX_PATH; return (0 == RegGetValueW(HKEY_CLASSES_ROOT, L"CLSID\\{72013A26-A94C-11d6-8540-A5E62932711D}\\InprocServer32", 0, RRF_RT_REG_SZ, 0, wszPath, &dwSize)); } EXTERN_C HANDLE WINAPI hook(unsigned mode, PDelayLoadInfo) { if (mode == dliNotePreLoadLibrary && !bModuleInited) { wchar_t wszPath[MAX_PATH]; GetModuleFileNameW(nullptr, wszPath, _countof(wszPath)); wchar_t* p = FindSlash(wszPath); if (p != nullptr) { // if we're launched from miranda, do nothing if (!lstrcmpiW(p+1, MIRANDA_PROCESS)) return 0; *p = 0; } if (!GetMirandaPath(wszPath)) return 0; if (!(p = FindSlash(wszPath))) return 0; // fall back to Plugins *p = 0; if (!(p = FindSlash(wszPath))) return 0; // fall back to miranda's root directory *p = 0; lstrcatW(wszPath, L"\\libs"); SetDllDirectoryW(wszPath); #ifdef _DEBUG lstrcatW(wszPath, L"\\ucrtbased.dll"); #else lstrcatW(wszPath, L"\\ucrtbase.dll"); #endif LoadLibraryW(wszPath); bModuleInited = true; } return 0; } EXTERN_C const PfnDliHook __pfnDliNotifyHook2 = (PfnDliHook)&hook; ///////////////////////////////////////////////////////////////////////////////////////// PLUGININFOEX pluginInfoEx = { sizeof(PLUGININFOEX), __PLUGIN_NAME, PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), __DESCRIPTION, __AUTHOR, __COPYRIGHT, __AUTHORWEB, UNICODE_AWARE, // {7993AB24-1FDA-428C-A89B-BE377A10BE3A} { 0x7993ab24, 0x1fda, 0x428c, { 0xa8, 0x9b, 0xbe, 0x37, 0x7a, 0x10, 0xbe, 0x3a }} }; CMPlugin::CMPlugin() : PLUGIN("shlext15", 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 = nullptr; 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 { HRegKey(HKEY hRoot, const wchar_t* ptszKey) : m_key(nullptr) { RegCreateKeyEx(hRoot, ptszKey, 0, nullptr, 0, KEY_SET_VALUE | KEY_CREATE_SUB_KEY, nullptr, &m_key, nullptr); } ~HRegKey() { if (m_key) RegCloseKey(m_key); } operator HKEY() const { return m_key; } private: HKEY m_key; }; char str1[100]; char str2[] = "{72013A26-A94C-11d6-8540-A5E62932711D}"; char str3[] = "miranda.shlext"; char str4[] = "Apartment"; STDAPI DllRegisterServer() { HRegKey k1(HKEY_CLASSES_ROOT, L"miranda.shlext"); if (k1 == nullptr) return E_FAIL; int str1len = sprintf_s(str1, sizeof(str1), "shlext %d.%d.%d.%d - shell context menu support for Miranda NG", __FILEVERSION_STRING); if (RegSetValueA(k1, nullptr, REG_SZ, str1, str1len)) return E_FAIL; if (RegSetValueA(k1, "CLSID", REG_SZ, str2, sizeof(str2))) return E_FAIL; ////////////////////////////////////////////////////////////////////////////////////// HRegKey kClsid(HKEY_CLASSES_ROOT, L"CLSID\\{72013A26-A94C-11d6-8540-A5E62932711D}"); if (kClsid == nullptr) return E_FAIL; if (RegSetValueA(kClsid, nullptr, REG_SZ, str3, sizeof(str3))) return E_FAIL; if (RegSetValueA(kClsid, "ProgID", REG_SZ, str3, sizeof(str3))) return E_FAIL; HRegKey kInprocServer(kClsid, L"InprocServer32"); if (kInprocServer == nullptr) return E_FAIL; wchar_t tszFileName[MAX_PATH]; GetModuleFileName(g_plugin.getInst(), tszFileName, _countof(tszFileName)); if (RegSetValueEx(kInprocServer, nullptr, 0, REG_SZ, (LPBYTE)tszFileName, sizeof(wchar_t) * (lstrlen(tszFileName) + 1))) return E_FAIL; if (RegSetValueExA(kInprocServer, "ThreadingModel", 0, REG_SZ, (uint8_t*)str4, sizeof(str4))) return E_FAIL; ////////////////////////////////////////////////////////////////////////////////////// if (RegSetValueA(HKEY_CLASSES_ROOT, "*\\shellex\\ContextMenuHandlers\\miranda.shlext", REG_SZ, str2, sizeof(str2))) return E_FAIL; if (RegSetValueA(HKEY_CLASSES_ROOT, "Directory\\shellex\\ContextMenuHandlers\\miranda.shlext", REG_SZ, str2, sizeof(str2))) return E_FAIL; ////////////////////////////////////////////////////////////////////////////////////// HRegKey k2(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"); if (k2 == nullptr) return E_FAIL; if (RegSetValueExA(k2, str2, 0, REG_SZ, (uint8_t*)str1, str1len)) return E_FAIL; return S_OK; } STDAPI DllUnregisterServer() { return RemoveCOMRegistryEntries(); } ///////////////////////////////////////////////////////////////////////////////////////// int CMPlugin::Load() { InvokeThreadServer(); HookEvent(ME_OPT_INITIALISE, OnOptionsInit); DllRegisterServer(); CheckRegisterServer(); return 0; }