ReactOS 0.4.15-dev-6663-gd1e9fe1
shlextdbg.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: shlextdbg
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Shell extension debug utility
5 * COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
6 */
7
8#include <windows.h>
9#include <shlobj.h>
10#include <atlbase.h> // thanks gcc
11#include <atlcom.h> // thanks gcc
12#include <atlstr.h>
13#include <atlsimpcoll.h>
14#include <conio.h>
15#include <shellutils.h>
16
18{
23};
24
25CLSID g_CLSID = { 0 };
31
33{
35 if (!SUCCEEDED(hr))
36 {
37 wprintf(L"Failed to create pidl from '%s': 0x%x\n", FileName, hr);
38 return hr;
39 }
40
41 CComPtr<IShellFolder> shellFolder;
42 PCUITEMID_CHILD childs;
43 hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &shellFolder), &childs);
44 if (!SUCCEEDED(hr))
45 {
46 wprintf(L"Failed to bind to parent: 0x%x\n", hr);
47 return hr;
48 }
49 hr = shellFolder->GetUIObjectOf(NULL, 1, &childs, IID_IDataObject, NULL, (PVOID*)&dataObject);
50 if (!SUCCEEDED(hr))
51 {
52 wprintf(L"Failed to query IDataObject: 0x%x\n", hr);
53 }
54 return hr;
55}
56
58{
59 CComPtr<IShellExtInit> spShellExtInit;
60 HRESULT hr;
61 if (g_DLL.IsEmpty())
62 {
63 hr = CoCreateInstance(g_CLSID, NULL, CLSCTX_ALL, IID_PPV_ARG(IShellExtInit, &spShellExtInit));
64 if (!SUCCEEDED(hr))
65 {
66 WCHAR Buffer[100];
68 wprintf(L"Failed to Create %s:IShellExtInit: 0x%x\n", Buffer, hr);
69 return hr;
70 }
71 }
72 else
73 {
74 typedef HRESULT (STDAPICALLTYPE *tDllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID *ppv);
76 if (!mod)
77 {
78 wprintf(L"Failed to Load %s:(0x%x)\n", g_DLL.GetString(), GetLastError());
79 return E_FAIL;
80 }
81 tDllGetClassObject DllGet = (tDllGetClassObject)GetProcAddress(mod, "DllGetClassObject");
82 if (!DllGet)
83 {
84 wprintf(L"%s does not export DllGetClassObject\n", g_DLL.GetString());
85 return E_FAIL;
86 }
87 CComPtr<IClassFactory> spClassFactory;
88 hr = DllGet(g_CLSID, IID_PPV_ARG(IClassFactory, &spClassFactory));
89 if (!SUCCEEDED(hr))
90 {
91 wprintf(L"Failed to create IClassFactory: 0x%x\n", hr);
92 return hr;
93 }
94 hr = spClassFactory->CreateInstance(NULL, IID_PPV_ARG(IShellExtInit, &spShellExtInit));
95 if (!SUCCEEDED(hr))
96 {
97 wprintf(L"Failed to Request IShellExtInit from IClassFactory: 0x%x\n", hr);
98 return hr;
99 }
100 }
101
102 CComPtr<IDataObject> spDataObject;
104 hr = CreateIDataObject(pidl, spDataObject, g_ShellExtInit.GetString());
105 if (!SUCCEEDED(hr))
106 return hr;
107
108 hr = spShellExtInit->Initialize(pidl, spDataObject, NULL);
109 if (!SUCCEEDED(hr))
110 {
111 wprintf(L"IShellExtInit->Initialize failed: 0x%x\n", hr);
112 return hr;
113 }
114 hr = spShellExtInit->QueryInterface(riid, ppv);
115 if (!SUCCEEDED(hr))
116 {
117 WCHAR Buffer[100];
119 wprintf(L"Failed to query %s from IShellExtInit: 0x%x\n", Buffer, hr);
120 }
121 return hr;
122}
123
124
128{
129 if (hwnd != g_ConsoleWindow)
130 {
131 DWORD pid = 0;
133 if (pid == GetCurrentProcessId())
134 {
135 g_Windows.Add(hwnd);
136 }
137 }
138 return TRUE;
139}
140
142{
143 /* Give the windows some time to spawn */
144 Sleep(2000);
146 while (true)
147 {
148 g_Windows.RemoveAll();
150 if (g_Windows.GetSize() == 0)
151 break;
152 Sleep(500);
153 }
154 wprintf(L"All windows closed (ignoring console window)\n");
155}
156
157
158
161{
162 g_Pages.Add(page);
163 if (lParam != (LPARAM)&g_Pages)
164 {
165 wprintf(L"Propsheet failed to pass lParam, got: 0x%Ix\n", lParam);
166 }
167 return TRUE;
168}
169
170static bool isCmdWithArg(int argc, WCHAR** argv, int& n, PCWSTR check, PCWSTR &arg)
171{
172 arg = NULL;
173 size_t len = wcslen(check);
174 if (!_wcsnicmp(argv[n] + 1, check, len))
175 {
176 PCWSTR cmd = argv[n] + len + 1;
177 if (*cmd == ':' || *cmd == '=')
178 {
179 arg = cmd + 1;
180 return true;
181 }
182 if (n + 1 < argc)
183 {
184 arg = argv[n+1];
185 n++;
186 return true;
187 }
188 wprintf(L"Command %s has no required argument!\n", check);
189 return false;
190 }
191 return false;
192}
193
194static bool isCmd(int argc, WCHAR** argv, int n, PCWSTR check)
195{
196 return !wcsicmp(argv[n] + 1, check);
197}
198
199static void PrintHelp(PCWSTR ExtraLine)
200{
201 if (ExtraLine)
202 wprintf(L"%s\n", ExtraLine);
203
204 wprintf(L"shlextdbg /clsid={clsid} [/dll=dllname] /IShellExtInit=filename |shlextype| |waitoptions|\n");
205 wprintf(L" {clsid}: The CLSID or ProgID of the object to create\n");
206 wprintf(L" dll: Optional dllname to create the object from, instead of CoCreateInstance\n");
207 wprintf(L" filename: The filename to pass to IShellExtInit->Initialze\n");
208 wprintf(L" shlextype: The type of shell extention to run:\n");
209 wprintf(L" /IShellPropSheetExt to create a property sheet\n");
210 wprintf(L" /IContextMenu=verb to activate the specified verb\n");
211 wprintf(L" waitoptions: Specify how to wait:\n");
212 wprintf(L" /infinite: Keep on waiting infinitely\n");
213 wprintf(L" /openwindows: Wait for all windows from the current application to close\n");
214 wprintf(L" /input: Wait for input\n");
215 wprintf(L"\n");
216}
217
218/*
219Examples:
220
221/clsid={513D916F-2A8E-4F51-AEAB-0CBC76FB1AF8} /IShellExtInit=C:\RosBE\Uninstall.exe /IShellPropSheetExt
222/clsid=CompressedFolder /IShellExtInit=e:\test.zip /IContextMenu=extract /openwindows
223/clsid=CompressedFolder /IShellExtInit=e:\test.zip /IContextMenu=extract /openwindows /dll=R:\build\dev\devenv\dll\shellext\zipfldr\Debug\zipfldr.dll
224
225*/
226extern "C" // and another hack for gcc
227int wmain(int argc, WCHAR **argv)
228{
229 bool failArgs = false;
230 for (int n = 1; n < argc; ++n)
231 {
232 WCHAR* cmd = argv[n];
233 if (cmd[0] == '-' || cmd[0] == '/')
234 {
235 PCWSTR arg;
236 if (isCmdWithArg(argc, argv, n, L"clsid", arg))
237 {
239 if (!SUCCEEDED(hr))
240 {
241 wprintf(L"Failed to convert %s to CLSID\n", arg);
242 failArgs = true;
243 }
244 }
245 else if (isCmdWithArg(argc, argv, n, L"dll", arg))
246 {
247 g_DLL = arg;
248 }
249 else if (isCmdWithArg(argc, argv, n, L"IShellExtInit", arg))
250 {
252 }
253 else if (isCmd(argc, argv, n, L"IShellPropSheetExt"))
254 {
256 }
257 else if (isCmdWithArg(argc, argv, n, L"IContextMenu", arg))
258 {
260 }
261 else if (isCmd(argc, argv, n, L"infinite"))
262 {
264 }
265 else if (isCmd(argc, argv, n, L"openwindows"))
266 {
268 }
269 else if (isCmd(argc, argv, n, L"input"))
270 {
272 }
273 else
274 {
275 wprintf(L"Unknown argument: %s\n", cmd);
276 failArgs = true;
277 }
278 }
279 }
280
281 if (failArgs)
282 {
284 return E_INVALIDARG;
285 }
286
287
288 CLSID EmptyCLSID = { 0 };
289 if (EmptyCLSID == g_CLSID)
290 {
291 PrintHelp(L"No CLSID specified");
292 return E_INVALIDARG;
293 }
294
296 {
297 PrintHelp(L"No filename specified");
298 return E_INVALIDARG;
299 }
300
304
305 HRESULT hr;
307 {
310 if (!SUCCEEDED(hr))
311 return hr;
312
313 hr = spSheetExt->AddPages(cb_AddPage, (LPARAM)&g_Pages);
314 if (!SUCCEEDED(hr))
315 {
316 wprintf(L"IShellPropSheetExt->AddPages failed: 0x%x\n", hr);
317 return hr;
318 }
319
320 USHORT ActivePage = HRESULT_CODE(hr);
321 PROPSHEETHEADERW psh = { 0 };
322
323 psh.dwSize = sizeof(psh);
325 psh.pszCaption = L"shlextdbg";
326 psh.phpage = g_Pages.GetData();
327 psh.nPages = g_Pages.GetSize();
328 psh.nStartPage = ActivePage ? (ActivePage-1) : 0;
329 hr = PropertySheetW(&psh);
330
331 wprintf(L"PropertySheetW returned: 0x%x\n", hr);
332 }
333 if (!g_ContextMenu.IsEmpty())
334 {
335 CComPtr<IContextMenu> spContextMenu;
336 hr = LoadAndInitialize(IID_PPV_ARG(IContextMenu, &spContextMenu));
337 if (!SUCCEEDED(hr))
338 return hr;
339
340 CMINVOKECOMMANDINFO cm = { sizeof(cm), 0 };
341 cm.lpVerb = g_ContextMenu.GetString();
342 cm.nShow = SW_SHOW;
343 hr = spContextMenu->InvokeCommand(&cm);
344
345 if (!SUCCEEDED(hr))
346 {
347 wprintf(L"IContextMenu->InvokeCommand failed: 0x%x\n", hr);
348 return hr;
349 }
350 wprintf(L"IContextMenu->InvokeCommand returned: 0x%x\n", hr);
351 }
352
353 switch (g_Wait)
354 {
355 case Wait_None:
356 break;
357 case Wait_Infinite:
358 while (true) {
359 Sleep(1000);
360 }
361 break;
362 case Wait_OpenWindows:
363 WaitWindows();
364 break;
365 case Wait_Input:
366 wprintf(L"Press any key to continue...\n");
367 _getch();
368 break;
369
370 }
371 return 0;
372}
static int argc
Definition: ServiceArgs.c:12
bool IsEmpty() const
Definition: atlsimpstr.h:389
Definition: bufpool.h:45
LPARAM lParam
Definition: combotst.c:139
BOOL WINAPI InitCommonControlsEx(const INITCOMMONCONTROLSEX *lpInitCtrls)
Definition: commctrl.c:893
#define E_INVALIDARG
Definition: ddrawi.h:101
#define E_FAIL
Definition: ddrawi.h:102
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
INT_PTR WINAPI PropertySheetW(LPCPROPSHEETHEADERW lppsh)
Definition: propsheet.c:2905
#define GetProcAddress(x, y)
Definition: compat.h:753
#define CALLBACK
Definition: compat.h:35
#define LoadLibraryW(x)
Definition: compat.h:747
#define wcsicmp
Definition: compat.h:15
HWND WINAPI DECLSPEC_HOTPATCH GetConsoleWindow(VOID)
Definition: console.c:2729
HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID iid, LPVOID *ppv)
Definition: compobj.c:3325
HRESULT WINAPI CoInitialize(LPVOID lpReserved)
Definition: compobj.c:1964
HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id)
Definition: compobj.c:2338
INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
Definition: compobj.c:2434
#define check(expected, result)
Definition: dplayx.c:32
#define STDAPICALLTYPE
Definition: guid.c:3
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLdouble n
Definition: glext.h:7729
GLenum GLsizei len
Definition: glext.h:6722
static int mod
Definition: i386-dis.c:1288
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
REFIID riid
Definition: atlbase.h:39
REFIID LPVOID * ppv
Definition: atlbase.h:39
#define SUCCEEDED(hr)
Definition: intsafe.h:50
void PrintHelp()
Definition: appwiz.c:21
#define argv
Definition: mplay32.c:18
struct _PSP * HPROPSHEETPAGE
Definition: mstask.idl:90
#define L(x)
Definition: ntvdm.h:50
const GUID IID_IDataObject
unsigned short USHORT
Definition: pedump.c:61
HRESULT WINAPI SHParseDisplayName(LPCWSTR pszName, IBindCtx *pbc, LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut)
Definition: pidl.c:1385
HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast)
Definition: pidl.c:1341
#define PSH_PROPTITLE
Definition: prsht.h:40
#define ICC_STANDARD_CLASSES
Definition: commctrl.h:73
#define ICC_LINK_CLASS
Definition: commctrl.h:74
#define REFIID
Definition: guiddef.h:118
#define REFCLSID
Definition: guiddef.h:117
int wmain()
_Check_return_ _CRTIMP int __cdecl _wcsnicmp(_In_reads_or_z_(_MaxCount) const wchar_t *_Str1, _In_reads_or_z_(_MaxCount) const wchar_t *_Str2, _In_ size_t _MaxCount)
int _getch()
Definition: getch.c:16
CLSID g_CLSID
Definition: shlextdbg.cpp:25
CStringA g_ContextMenu
Definition: shlextdbg.cpp:29
static BOOL CALLBACK cb_AddPage(HPROPSHEETPAGE page, LPARAM lParam)
Definition: shlextdbg.cpp:160
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
Definition: shlextdbg.cpp:127
WaitType g_Wait
Definition: shlextdbg.cpp:30
WaitType
Definition: shlextdbg.cpp:18
@ Wait_OpenWindows
Definition: shlextdbg.cpp:21
@ Wait_Input
Definition: shlextdbg.cpp:22
@ Wait_Infinite
Definition: shlextdbg.cpp:20
@ Wait_None
Definition: shlextdbg.cpp:19
static bool isCmdWithArg(int argc, WCHAR **argv, int &n, PCWSTR check, PCWSTR &arg)
Definition: shlextdbg.cpp:170
CSimpleArray< HWND > g_Windows
Definition: shlextdbg.cpp:125
static bool isCmd(int argc, WCHAR **argv, int n, PCWSTR check)
Definition: shlextdbg.cpp:194
CStringW g_ShellExtInit
Definition: shlextdbg.cpp:27
HRESULT LoadAndInitialize(REFIID riid, LPVOID *ppv)
Definition: shlextdbg.cpp:57
bool g_bIShellPropSheetExt
Definition: shlextdbg.cpp:28
HWND g_ConsoleWindow
Definition: shlextdbg.cpp:126
HRESULT CreateIDataObject(CComHeapPtr< ITEMIDLIST > &pidl, CComPtr< IDataObject > &dataObject, PCWSTR FileName)
Definition: shlextdbg.cpp:32
CSimpleArray< HPROPSHEETPAGE > g_Pages
Definition: shlextdbg.cpp:159
CStringW g_DLL
Definition: shlextdbg.cpp:26
void WaitWindows()
Definition: shlextdbg.cpp:141
HRESULT hr
Definition: shlfolder.c:183
const ITEMID_CHILD UNALIGNED * PCUITEMID_CHILD
Definition: shtypes.idl:70
#define _countof(array)
Definition: sndvol32.h:68
DWORD dwSize
Definition: prsht.h:293
DWORD dwFlags
Definition: prsht.h:294
HPROPSHEETPAGE * phpage
Definition: prsht.h:309
UINT nStartPage
Definition: prsht.h:304
LPCWSTR pszCaption
Definition: prsht.h:301
Definition: ftp_var.h:139
Definition: module.h:576
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:790
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define wprintf(...)
Definition: whoami.c:18
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
DWORD WINAPI GetCurrentProcessId(void)
Definition: proc.c:1158
DWORD WINAPI GetWindowThreadProcessId(HWND hWnd, PDWORD lpdwProcessId)
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
_In_ ULONG_PTR _In_ ULONG _Out_ ULONG_PTR * pid
Definition: winddi.h:3837
LONG_PTR LPARAM
Definition: windef.h:208
void * arg
Definition: msvc.h:10
#define HRESULT_CODE(hr)
Definition: winerror.h:76
BOOL WINAPI EnumWindows(_In_ WNDENUMPROC lpEnumFunc, _In_ LPARAM lParam)
#define SW_SHOW
Definition: winuser.h:769
#define IID_PPV_ARG(Itype, ppType)
__wchar_t WCHAR
Definition: xmlstorage.h:180