* Addendum to r65483.
[reactos.git] / dll / win32 / browseui / desktopipc.cpp
1 #include "precomp.h"
2 #include <shlwapi.h>
3 #include <shlwapi_undoc.h>
4
5 #define PROXY_DESKTOP_CLASS L"Proxy Desktop"
6
7 BOOL g_SeparateFolders = FALSE;
8
9 // fields indented more are unknown ;P
10 struct HNFBlock
11 {
12 UINT cbSize;
13 DWORD offset4;
14 DWORD offset8;
15 DWORD offsetC;
16 DWORD offset10;
17 DWORD offset14;
18 DWORD offset18;
19 DWORD offset1C;
20 DWORD offset20;
21 DWORD offset24;
22 DWORD offset28;
23 DWORD offset2C;
24 DWORD offset30;
25 UINT directoryPidlLength;
26 UINT pidlSize7C;
27 UINT pidlSize80;
28 UINT pathLength;
29 };
30
31 extern DWORD WINAPI BrowserThreadProc(LPVOID lpThreadParameter);
32
33 class CProxyDesktop :
34 public CComObjectRootEx<CComMultiThreadModelNoCS>,
35 public CWindowImpl < CProxyDesktop, CWindow, CFrameWinTraits >
36 {
37 IEThreadParamBlock * m_Parameters;
38
39 LPITEMIDLIST m_rootPidl;
40
41 public:
42 CProxyDesktop(IEThreadParamBlock * parameters) :
43 m_Parameters(parameters)
44 {
45
46 }
47
48 virtual ~CProxyDesktop()
49 {
50 }
51
52 LRESULT OnMessage1037(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
53 {
54 DbgPrint("Proxy Desktop message 1037.\n");
55 bHandled = TRUE;
56 return TRUE;
57 }
58
59 LRESULT OnOpenNewWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
60 {
61 DbgPrint("Proxy Desktop message 1035 received.\n");
62 bHandled = TRUE;
63 SHOnCWMCommandLine((HANDLE) lParam);
64 return 0;
65 }
66
67 DECLARE_WND_CLASS_EX(PROXY_DESKTOP_CLASS, CS_SAVEBITS | CS_DROPSHADOW, COLOR_3DFACE)
68
69 BEGIN_MSG_MAP(CProxyDesktop)
70 MESSAGE_HANDLER(WM_EXPLORER_1037, OnMessage1037)
71 MESSAGE_HANDLER(WM_EXPLORER_OPEN_NEW_WINDOW, OnOpenNewWindow)
72 END_MSG_MAP()
73 };
74
75 static CProxyDesktop * CreateProxyDesktop(IEThreadParamBlock * parameters)
76 {
77 return new CProxyDesktop(parameters);
78 }
79
80 HWND FindShellProxy(LPITEMIDLIST pidl)
81 {
82 if (!g_SeparateFolders)
83 {
84 HWND shell = GetShellWindow();
85
86 if (shell)
87 {
88 DbgPrint("Found main desktop.\n");
89 return shell;
90 }
91 }
92 else
93 {
94 DbgPrint("Separate folders setting enabled. Ignoring main desktop.\n");
95 }
96
97 HWND proxy = FindWindow(PROXY_DESKTOP_CLASS, NULL);
98 if (proxy)
99 {
100 DbgPrint("Found proxy desktop.\n");
101 return proxy;
102 }
103
104 return NULL;
105 }
106
107 HANDLE MakeSharedPacket(IEThreadParamBlock * threadParams, LPCWSTR strPath, int dwProcessId)
108 {
109 HNFBlock* hnfData;
110 UINT sharedBlockSize = sizeof(*hnfData);
111 UINT directoryPidlLength = 0;
112 UINT pidlSize7C = 0;
113 UINT pidlSize80 = 0;
114 UINT pathLength = 0;
115 LPITEMIDLIST pidl80 = threadParams->offset80;
116
117 // Count the total length of the message packet
118
119 // directory PIDL
120 if (threadParams->directoryPIDL)
121 {
122 directoryPidlLength = ILGetSize(threadParams->directoryPIDL);
123 sharedBlockSize += directoryPidlLength;
124 DbgPrint("directoryPidlLength=%d\n", directoryPidlLength);
125 }
126
127 // another PIDL
128 if (threadParams->offset7C)
129 {
130 pidlSize7C = ILGetSize(threadParams->offset7C);
131 sharedBlockSize += pidlSize7C;
132 DbgPrint("pidlSize7C=%d\n", pidlSize7C);
133 }
134
135 // This flag indicates the presence of another pidl?
136 if (!(threadParams->offset84 & 0x8000))
137 {
138 if (pidl80)
139 {
140 pidlSize80 = ILGetSize(pidl80);
141 sharedBlockSize += pidlSize80;
142 DbgPrint("pidlSize80=%d\n", pidlSize7C);
143 }
144 }
145 else
146 {
147 DbgPrint("pidl80 sent by value = %p\n", pidl80);
148 pidlSize80 = 4;
149 sharedBlockSize += pidlSize80;
150 }
151
152 // The path string
153 if (strPath)
154 {
155 pathLength = 2 * lstrlenW(strPath) + 2;
156 sharedBlockSize += pathLength;
157 DbgPrint("pathLength=%d\n", pidlSize7C);
158 }
159
160 DbgPrint("sharedBlockSize=%d\n", sharedBlockSize);
161
162 // Allocate and fill the shared section
163 HANDLE hShared = SHAllocShared(0, sharedBlockSize, dwProcessId);
164 if (!hShared)
165 {
166 DbgPrint("Shared section alloc error.\n");
167 return 0;
168 }
169
170 PBYTE target = (PBYTE) SHLockShared(hShared, dwProcessId);
171 if (!target)
172 {
173 DbgPrint("Shared section lock error. %d\n", GetLastError());
174 SHFreeShared(hShared, dwProcessId);
175 return 0;
176 }
177
178 // Basic information
179 hnfData = (HNFBlock*) target;
180 hnfData->cbSize = sharedBlockSize;
181 hnfData->offset4 = (DWORD) (threadParams->dwFlags);
182 hnfData->offset8 = (DWORD) (threadParams->offset8);
183 hnfData->offsetC = (DWORD) (threadParams->offset74);
184 hnfData->offset10 = (DWORD) (threadParams->offsetD8);
185 hnfData->offset14 = (DWORD) (threadParams->offset84);
186 hnfData->offset18 = (DWORD) (threadParams->offset88);
187 hnfData->offset1C = (DWORD) (threadParams->offset8C);
188 hnfData->offset20 = (DWORD) (threadParams->offset90);
189 hnfData->offset24 = (DWORD) (threadParams->offset94);
190 hnfData->offset28 = (DWORD) (threadParams->offset98);
191 hnfData->offset2C = (DWORD) (threadParams->offset9C);
192 hnfData->offset30 = (DWORD) (threadParams->offsetA0);
193 hnfData->directoryPidlLength = 0;
194 hnfData->pidlSize7C = 0;
195 hnfData->pidlSize80 = 0;
196 hnfData->pathLength = 0;
197 target += sizeof(*hnfData);
198
199 // Copy the directory pidl contents
200 if (threadParams->directoryPIDL)
201 {
202 memcpy(target, threadParams->directoryPIDL, directoryPidlLength);
203 target += directoryPidlLength;
204 hnfData->directoryPidlLength = directoryPidlLength;
205 }
206
207 // Copy the other pidl contents
208 if (threadParams->offset7C)
209 {
210 memcpy(target, threadParams->offset7C, pidlSize7C);
211 target += pidlSize7C;
212 hnfData->pidlSize7C = pidlSize7C;
213 }
214
215 // copy the third pidl
216 if (threadParams->offset84 & 0x8000)
217 {
218 *(LPITEMIDLIST*) target = pidl80;
219 target += pidlSize80;
220 hnfData->pidlSize80 = pidlSize80;
221 }
222 else if (pidl80)
223 {
224 memcpy(target, pidl80, pidlSize80);
225 target += pidlSize80;
226 hnfData->pidlSize80 = pidlSize80;
227 }
228
229 // and finally the path string
230 if (strPath)
231 {
232 memcpy(target, strPath, pathLength);
233 hnfData->pathLength = pathLength;
234 }
235
236 SHUnlockShared(hnfData);
237
238 return hShared;
239 }
240
241 PIE_THREAD_PARAM_BLOCK ParseSharedPacket(HANDLE hData)
242 {
243 HNFBlock * hnfData;
244 PBYTE block;
245 int pid;
246 PIE_THREAD_PARAM_BLOCK params = NULL;
247
248 if (!hData)
249 goto cleanup0;
250
251 pid = GetCurrentProcessId();
252 block = (PBYTE) SHLockShared(hData, pid);
253
254 hnfData = (HNFBlock *) block;
255 if (!block)
256 goto cleanup2;
257
258 if (hnfData->cbSize < sizeof(HNFBlock))
259 goto cleanup2;
260
261 params = SHCreateIETHREADPARAM(0, hnfData->offset8, 0, 0);
262 if (!params)
263 goto cleanup2;
264
265 params->dwFlags = hnfData->offset4;
266 params->offset8 = hnfData->offset8;
267 params->offset74 = hnfData->offsetC;
268 params->offsetD8 = hnfData->offset10;
269 params->offset84 = hnfData->offset14;
270 params->offset88 = hnfData->offset18;
271 params->offset8C = hnfData->offset1C;
272 params->offset90 = hnfData->offset20;
273 params->offset94 = hnfData->offset24;
274 params->offset98 = hnfData->offset28;
275 params->offset9C = hnfData->offset2C;
276 params->offsetA0 = hnfData->offset30;
277
278 block += sizeof(*hnfData);
279 if (hnfData->directoryPidlLength)
280 {
281 LPITEMIDLIST pidl = NULL;
282 if (*block)
283 pidl = ILClone((LPITEMIDLIST) block);
284 params->directoryPIDL = pidl;
285
286 block += hnfData->directoryPidlLength;
287 }
288
289 if (hnfData->pidlSize7C)
290 {
291 LPITEMIDLIST pidl = NULL;
292 if (*block)
293 pidl = ILClone((LPITEMIDLIST) block);
294 params->offset7C = pidl;
295
296 block += hnfData->pidlSize80;
297 }
298
299 if (hnfData->pidlSize80)
300 {
301 if (!(params->offset84 & 0x8000))
302 {
303 params->offset80 = *(LPITEMIDLIST *) block;
304 }
305 else
306 {
307 LPITEMIDLIST pidl = NULL;
308 if (*block)
309 pidl = ILClone((LPITEMIDLIST) block);
310 params->offset80 = pidl;
311 }
312
313 block += hnfData->pidlSize80;
314 }
315
316 if (hnfData->pathLength)
317 {
318 CComPtr<IShellFolder> psfDesktop;
319 PWSTR strPath = (PWSTR) block;
320
321 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
322 {
323 params->directoryPIDL = NULL;
324 goto cleanup0;
325 }
326
327 if (FAILED(psfDesktop->ParseDisplayName(NULL, NULL, strPath, NULL, &params->directoryPIDL, NULL)))
328 {
329 params->directoryPIDL = NULL;
330 goto cleanup0;
331 }
332 }
333
334 cleanup2:
335 SHUnlockShared(hnfData);
336 SHFreeShared(hData, pid);
337
338 cleanup0:
339 if (!params->directoryPIDL)
340 {
341 SHDestroyIETHREADPARAM(params);
342 return NULL;
343 }
344
345 return params;
346 }
347
348 /*************************************************************************
349 * SHCreateIETHREADPARAM [BROWSEUI.123]
350 */
351 extern "C" IEThreadParamBlock *WINAPI SHCreateIETHREADPARAM(
352 long param8, long paramC, IUnknown *param10, IUnknown *param14)
353 {
354 IEThreadParamBlock *result;
355
356 DbgPrint("SHCreateIETHREADPARAM\n");
357
358 result = (IEThreadParamBlock *) LocalAlloc(LMEM_ZEROINIT, 256);
359 if (result == NULL)
360 return NULL;
361 result->offset0 = param8;
362 result->offset8 = paramC;
363 result->offsetC = param10;
364 if (param10 != NULL)
365 param10->AddRef();
366 result->offset14 = param14;
367 if (param14 != NULL)
368 param14->AddRef();
369 return result;
370 }
371
372 /*************************************************************************
373 * SHCloneIETHREADPARAM [BROWSEUI.124]
374 */
375 extern "C" IEThreadParamBlock *WINAPI SHCloneIETHREADPARAM(IEThreadParamBlock *param)
376 {
377 IEThreadParamBlock *result;
378
379 DbgPrint("SHCloneIETHREADPARAM\n");
380
381 result = (IEThreadParamBlock *) LocalAlloc(LMEM_FIXED, 256);
382 if (result == NULL)
383 return NULL;
384 memcpy(result, param, 0x40 * 4);
385 if (result->directoryPIDL != NULL)
386 result->directoryPIDL = ILClone(result->directoryPIDL);
387 if (result->offset7C != NULL)
388 result->offset7C = ILClone(result->offset7C);
389 if (result->offset80 != NULL)
390 result->offset80 = ILClone(result->offset80);
391 if (result->offset70 != NULL)
392 result->offset70->AddRef();
393 #if 0
394 if (result->offsetC != NULL)
395 result->offsetC->Method2C();
396 #endif
397 return result;
398 }
399
400 /*************************************************************************
401 * SHDestroyIETHREADPARAM [BROWSEUI.126]
402 */
403 extern "C" void WINAPI SHDestroyIETHREADPARAM(IEThreadParamBlock *param)
404 {
405 DbgPrint("SHDestroyIETHREADPARAM\n");
406
407 if (param == NULL)
408 return;
409 if (param->directoryPIDL != NULL)
410 ILFree(param->directoryPIDL);
411 if (param->offset7C != NULL)
412 ILFree(param->offset7C);
413 if ((param->dwFlags & 0x80000) == 0 && param->offset80 != NULL)
414 ILFree(param->offset80);
415 if (param->offset14 != NULL)
416 param->offset14->Release();
417 if (param->offset70 != NULL)
418 param->offset70->Release();
419 if (param->offset78 != NULL)
420 param->offset78->Release();
421 if (param->offsetC != NULL)
422 param->offsetC->Release();
423 if (param->offsetF8 != NULL)
424 param->offsetF8->Release();
425 LocalFree(param);
426 }
427
428 /*************************************************************************
429 * SHOnCWMCommandLine [BROWSEUI.127]
430 */
431 extern "C" BOOL WINAPI SHOnCWMCommandLine(HANDLE hSharedInfo)
432 {
433 DbgPrint("SHOnCWMCommandLine\n");
434
435 PIE_THREAD_PARAM_BLOCK params = ParseSharedPacket(hSharedInfo);
436
437 if (params)
438 return SHOpenFolderWindow(params);
439
440 SHDestroyIETHREADPARAM(params);
441
442 return FALSE;
443 }
444
445 /*************************************************************************
446 * SHOpenFolderWindow [BROWSEUI.102]
447 * see SHOpenNewFrame below for remarks
448 */
449 extern "C" HRESULT WINAPI SHOpenFolderWindow(PIE_THREAD_PARAM_BLOCK parameters)
450 {
451 HANDLE threadHandle;
452 DWORD threadID;
453
454 WCHAR debugStr[MAX_PATH + 1];
455 SHGetPathFromIDListW(parameters->directoryPIDL, debugStr);
456
457 DbgPrint("SHOpenFolderWindow %p(%S)\n", parameters->directoryPIDL, debugStr);
458
459 PIE_THREAD_PARAM_BLOCK paramsCopy = SHCloneIETHREADPARAM(parameters);
460
461 SHGetInstanceExplorer(&(paramsCopy->offsetF8));
462 threadHandle = CreateThread(NULL, 0x10000, BrowserThreadProc, paramsCopy, 0, &threadID);
463 if (threadHandle != NULL)
464 {
465 CloseHandle(threadHandle);
466 return S_OK;
467 }
468 SHDestroyIETHREADPARAM(paramsCopy);
469 return E_FAIL;
470 }
471
472 // 75FA56C1h
473 // (pidl, 0, -1, 1)
474 // this function should handle creating a new process if needed, but I'm leaving that out for now
475 // this function always opens a new window - it does NOT check for duplicates
476 /*************************************************************************
477 * SHOpenNewFrame [BROWSEUI.103]
478 */
479 extern "C" HRESULT WINAPI SHOpenNewFrame(LPITEMIDLIST pidl, IUnknown *paramC, long param10, DWORD dwFlags)
480 {
481 IEThreadParamBlock *parameters;
482
483 DbgPrint("SHOpenNewFrame\n");
484
485 parameters = SHCreateIETHREADPARAM(0, 1, paramC, NULL);
486 if (parameters == NULL)
487 {
488 ILFree(pidl);
489 return E_OUTOFMEMORY;
490 }
491 if (paramC != NULL)
492 parameters->offset10 = param10;
493 parameters->directoryPIDL = pidl;
494 parameters->dwFlags = dwFlags;
495
496 HRESULT hr = SHOpenFolderWindow(parameters);
497
498 SHDestroyIETHREADPARAM(parameters);
499
500 return hr;
501 }
502
503 /*************************************************************************
504 * SHCreateFromDesktop [BROWSEUI.106]
505 * parameter is a FolderInfo
506 */
507 BOOL WINAPI SHCreateFromDesktop(ExplorerCommandLineParseResults * parseResults)
508 {
509 DbgPrint("SHCreateFromDesktop\n");
510
511 IEThreadParamBlock * parameters = SHCreateIETHREADPARAM(0, 0, 0, 0);
512 if (!parameters)
513 return FALSE;
514
515 PCWSTR strPath = NULL;
516 if (parseResults->dwFlags & SH_EXPLORER_CMDLINE_FLAG_STRING)
517 {
518 if (parseResults->pidlPath)
519 {
520 WARN("strPath and pidlPath are both assigned. This shouldn't happen.\n");
521 }
522
523 strPath = parseResults->strPath;
524 }
525
526 parameters->dwFlags = parseResults->dwFlags;
527 parameters->offset8 = parseResults->offsetC;
528
529 LPITEMIDLIST pidl = parseResults->pidlPath ? ILClone(parseResults->pidlPath) : NULL;
530 if (!pidl && parseResults->dwFlags & SH_EXPLORER_CMDLINE_FLAG_STRING)
531 {
532 if (parseResults->strPath && parseResults->strPath[0])
533 {
534 pidl = ILCreateFromPathW(parseResults->strPath);
535 }
536 }
537
538 parameters->directoryPIDL = pidl;
539
540 // Try to find the owner of the idlist, if we aren't running /SEPARATE
541 HWND desktop = NULL;
542 if (!(parseResults->dwFlags & SH_EXPLORER_CMDLINE_FLAG_SEPARATE))
543 desktop = FindShellProxy(parameters->directoryPIDL);
544
545 // If found, ask it to open the new window
546 if (desktop)
547 {
548 DbgPrint("Found desktop hwnd=%p\n", desktop);
549
550 DWORD dwProcessId;
551
552 GetWindowThreadProcessId(desktop, &dwProcessId);
553 AllowSetForegroundWindow(dwProcessId);
554
555 HANDLE hShared = MakeSharedPacket(parameters, strPath, dwProcessId);
556 if (hShared)
557 {
558 DbgPrint("Sending open message...\n");
559
560 PostMessageW(desktop, WM_EXPLORER_OPEN_NEW_WINDOW, 0, (LPARAM) hShared);
561 }
562
563 SHDestroyIETHREADPARAM(parameters);
564 return TRUE;
565 }
566
567 DbgPrint("Desktop not found or separate flag requested.\n");
568
569 // Else, start our own message loop!
570 HRESULT hr = CoInitialize(NULL);
571 CProxyDesktop * proxy = CreateProxyDesktop(parameters);
572 if (proxy)
573 {
574 LONG refCount;
575 CComPtr<IUnknown> thread;
576 if (SHCreateThreadRef(&refCount, &thread) >= 0)
577 {
578 SHSetInstanceExplorer(thread);
579 if (strPath)
580 parameters->directoryPIDL = ILCreateFromPath(strPath);
581 SHOpenFolderWindow(parameters);
582 parameters = NULL;
583 thread.Release();
584 }
585
586 MSG Msg;
587 while (GetMessageW(&Msg, 0, 0, 0) && refCount)
588 {
589 TranslateMessage(&Msg);
590 DispatchMessageW(&Msg);
591 }
592
593 delete proxy;
594 }
595
596 if (SUCCEEDED(hr))
597 CoUninitialize();
598
599 SHDestroyIETHREADPARAM(parameters);
600
601 return TRUE;
602 }