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