Last active
June 16, 2018 12:02
-
-
Save learn-more/eb1f56b4be51ac9d5ea784ae5b97cf29 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
#include <objbase.h> | |
#include <shlobj.h> | |
#include <shlwapi.h> | |
#include <shellapi.h> | |
#include <atlbase.h> | |
#include <atlcom.h> | |
#include <atlwin.h> | |
#include <atlsimpcoll.h> | |
# define IID_PPV_ARG(Itype, ppType) IID_##Itype, reinterpret_cast<void**>((static_cast<Itype**>(ppType))) | |
#define PRINT_FAILURE_HR(expr, hr) wprintf(L"%S failed with 0x%x\n", expr, hr) | |
#define ABORT_IF_FAILED(expr) \ | |
do { \ | |
HRESULT _hr = (expr);\ | |
if (!SUCCEEDED(_hr)) { \ | |
PRINT_FAILURE_HR(#expr, _hr); \ | |
return; \ | |
} \ | |
} while (0); | |
#define ABORT_IF_FAILED_HR(expr) \ | |
do { \ | |
HRESULT _hr = (expr);\ | |
if (!SUCCEEDED(_hr)) { \ | |
PRINT_FAILURE_HR(#expr, _hr); \ | |
return _hr; \ | |
} \ | |
} while (0); | |
static CSimpleArray<HPROPSHEETPAGE> g_Pages; | |
static BOOL CALLBACK cb_AddPage(HPROPSHEETPAGE page, LPARAM lParam) | |
{ | |
g_Pages.Add(page); | |
return TRUE; | |
} | |
static HRESULT CreateIDataObject(CComHeapPtr<ITEMIDLIST>& pidl, CComPtr<IDataObject>& dataObject, PCWSTR FileName) | |
{ | |
CComPtr<IShellFolder> desktopFolder; | |
ABORT_IF_FAILED_HR(SHGetDesktopFolder(&desktopFolder)); | |
ABORT_IF_FAILED_HR(desktopFolder->ParseDisplayName(NULL, NULL, (LPWSTR)FileName, NULL, &pidl, NULL)); | |
CComPtr<IShellFolder> shellFolder; | |
PCUITEMID_CHILD childs; | |
ABORT_IF_FAILED_HR(SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &shellFolder), &childs)); | |
ABORT_IF_FAILED_HR(shellFolder->GetUIObjectOf(NULL, 1, &childs, IID_IDataObject, NULL, (PVOID*)&dataObject)); | |
return S_OK; | |
} | |
class CDllWrapper | |
{ | |
public: | |
HMODULE hMod; | |
CDllWrapper(PCWSTR ModuleName) | |
{ | |
hMod = ::LoadLibraryW(ModuleName); | |
} | |
~CDllWrapper() | |
{ | |
if (hMod) | |
::FreeLibrary(hMod); | |
} | |
}; | |
typedef HRESULT(STDAPICALLTYPE *tDllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID *ppv); | |
void run_shellext(PCWSTR ShellextModule, REFGUID ShellextGuid, PCWSTR ShellextTarget) | |
{ | |
CDllWrapper dll(ShellextModule); | |
if (!dll.hMod) | |
{ | |
wprintf(L"Failed to load %s with 0x%x\n", ShellextModule, GetLastError()); | |
return; | |
} | |
tDllGetClassObject DllGet = (tDllGetClassObject)GetProcAddress(dll.hMod, "DllGetClassObject"); | |
if (!DllGet) | |
{ | |
wprintf(L"Failed to retrieve DllGetClassObject from %s\n", ShellextModule); | |
return; | |
} | |
{ | |
CComPtr<IShellPropSheetExt> pSheetExt; | |
CComPtr<IClassFactory> pClassFactory; | |
ABORT_IF_FAILED(DllGet(ShellextGuid, IID_PPV_ARG(IClassFactory, &pClassFactory))); | |
ABORT_IF_FAILED(pClassFactory->CreateInstance(NULL, IID_PPV_ARG(IShellPropSheetExt, &pSheetExt))); | |
CComPtr<IShellExtInit> pShellext; | |
ABORT_IF_FAILED(pSheetExt->QueryInterface(IID_PPV_ARG(IShellExtInit, &pShellext))); | |
CComPtr<IDataObject> dataObject; | |
CComHeapPtr<ITEMIDLIST> pidl; | |
HRESULT hr = CreateIDataObject(pidl, dataObject, ShellextTarget); | |
if (!SUCCEEDED(hr)) | |
return; | |
ABORT_IF_FAILED(pShellext->Initialize(pidl, dataObject, NULL)); | |
ABORT_IF_FAILED(pSheetExt->AddPages(cb_AddPage, NULL)); | |
} | |
PROPSHEETHEADER psh = { 0 }; | |
psh.dwSize = sizeof(psh); | |
psh.dwFlags = PSH_PROPTITLE; | |
psh.pszCaption = ShellextTarget; | |
psh.phpage = g_Pages.GetData(); | |
psh.nPages = g_Pages.GetSize(); | |
PropertySheetW(&psh); | |
} | |
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' ""version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") | |
class CCoInitialize | |
{ | |
public: | |
CCoInitialize(DWORD dwCoInit = COINIT_APARTMENTTHREADED) : m_hr(CoInitializeEx(NULL, dwCoInit)) { } | |
~CCoInitialize() { if (SUCCEEDED(m_hr)) CoUninitialize(); } | |
operator HRESULT() const { return m_hr; } | |
HRESULT m_hr; | |
}; | |
bool match_arg(wchar_t* arg, const wchar_t* option) | |
{ | |
if (arg && (*arg == '/' || *arg == '-')) | |
{ | |
return !_wcsicmp(arg + 1, option); | |
} | |
return false; | |
} | |
int wmain(int argc, wchar_t* argv[]) | |
{ | |
INITCOMMONCONTROLSEX icc = { sizeof(icc), ICC_LINK_CLASS | ICC_STANDARD_CLASSES }; | |
InitCommonControlsEx(&icc); | |
CCoInitialize coinit; | |
bool show_help = false; | |
for (int n = 1; n < argc;) | |
{ | |
wchar_t* arg = argv[n]; | |
if (match_arg(arg, L"shellext")) | |
{ | |
if (n + 3 < argc) | |
{ | |
const wchar_t* ext_dll = argv[n + 1]; | |
const wchar_t* ext_clsid = argv[n + 2]; | |
const wchar_t* target = argv[n + 3]; | |
GUID clsid; | |
HRESULT hr = CLSIDFromString(ext_clsid, &clsid); | |
if (SUCCEEDED(hr)) | |
{ | |
run_shellext(ext_dll, clsid, target); | |
} | |
else | |
{ | |
PRINT_FAILURE_HR("CLSIDFromString", hr); | |
show_help = true; | |
} | |
} | |
else | |
{ | |
show_help = true; | |
} | |
n += 4; | |
} | |
else if (match_arg(arg, L"h") || match_arg(arg, L"help")) | |
{ | |
show_help = true; | |
++n; | |
} | |
else | |
{ | |
++n; | |
} | |
} | |
if (show_help) | |
{ | |
wprintf(L"Usage: %s [/shellext extdll {GUID} target] [/help]\n", argv[0]); | |
wprintf(L" /shellext - Create {GUID} from 'extdll', and display the properties for 'target'\n"); | |
wprintf(L" /help - display this help\n"); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment