3 #include <shlwapi_undoc.h>
5 #define PROXY_DESKTOP_CLASS L"Proxy Desktop"
7 BOOL g_SeparateFolders
= FALSE
;
8 HWND g_hwndProxyDesktop
= NULL
;
10 // fields indented more are unknown ;P
26 UINT directoryPidlLength
;
33 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
34 public CWindowImpl
< CProxyDesktop
, CWindow
, CFrameWinTraits
>
38 CProxyDesktop(IEThreadParamBlock
* parameters
)
42 virtual ~CProxyDesktop()
46 LRESULT
OnMessage1037(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
48 TRACE("Proxy Desktop message 1037.\n");
53 LRESULT
OnOpenNewWindow(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
55 TRACE("Proxy Desktop message 1035 received.\n");
57 SHOnCWMCommandLine((HANDLE
) lParam
);
61 DECLARE_WND_CLASS_EX(PROXY_DESKTOP_CLASS
, CS_SAVEBITS
| CS_DROPSHADOW
, COLOR_3DFACE
)
63 BEGIN_MSG_MAP(CProxyDesktop
)
64 MESSAGE_HANDLER(WM_EXPLORER_1037
, OnMessage1037
)
65 MESSAGE_HANDLER(WM_EXPLORER_OPEN_NEW_WINDOW
, OnOpenNewWindow
)
69 HWND
FindShellProxy(LPITEMIDLIST pidl
)
71 /* If there is a proxy desktop in the current process use it */
72 if (g_hwndProxyDesktop
)
73 return g_hwndProxyDesktop
;
75 /* Try to find the desktop of the main explorer process */
76 if (!g_SeparateFolders
)
78 HWND shell
= GetShellWindow();
82 TRACE("Found main desktop.\n");
88 TRACE("Separate folders setting enabled. Ignoring main desktop.\n");
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
);
95 TRACE("Found proxy desktop.\n");
102 HANDLE
MakeSharedPacket(IEThreadParamBlock
* threadParams
, LPCWSTR strPath
, int dwProcessId
)
105 UINT sharedBlockSize
= sizeof(*hnfData
);
106 UINT directoryPidlLength
= 0;
110 LPITEMIDLIST pidl80
= threadParams
->offset80
;
112 // Count the total length of the message packet
115 if (threadParams
->directoryPIDL
)
117 directoryPidlLength
= ILGetSize(threadParams
->directoryPIDL
);
118 sharedBlockSize
+= directoryPidlLength
;
119 TRACE("directoryPidlLength=%d\n", directoryPidlLength
);
123 if (threadParams
->offset7C
)
125 pidlSize7C
= ILGetSize(threadParams
->offset7C
);
126 sharedBlockSize
+= pidlSize7C
;
127 TRACE("pidlSize7C=%d\n", pidlSize7C
);
130 // This flag indicates the presence of another pidl?
131 if (!(threadParams
->offset84
& 0x8000))
135 pidlSize80
= ILGetSize(pidl80
);
136 sharedBlockSize
+= pidlSize80
;
137 TRACE("pidlSize80=%d\n", pidlSize7C
);
142 TRACE("pidl80 sent by value = %p\n", pidl80
);
144 sharedBlockSize
+= pidlSize80
;
150 pathLength
= 2 * lstrlenW(strPath
) + 2;
151 sharedBlockSize
+= pathLength
;
152 TRACE("pathLength=%d\n", pidlSize7C
);
155 TRACE("sharedBlockSize=%d\n", sharedBlockSize
);
157 // Allocate and fill the shared section
158 HANDLE hShared
= SHAllocShared(0, sharedBlockSize
, dwProcessId
);
161 ERR("Shared section alloc error.\n");
165 PBYTE target
= (PBYTE
) SHLockShared(hShared
, dwProcessId
);
168 ERR("Shared section lock error. %d\n", GetLastError());
169 SHFreeShared(hShared
, dwProcessId
);
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
);
194 // Copy the directory pidl contents
195 if (threadParams
->directoryPIDL
)
197 memcpy(target
, threadParams
->directoryPIDL
, directoryPidlLength
);
198 target
+= directoryPidlLength
;
199 hnfData
->directoryPidlLength
= directoryPidlLength
;
202 // Copy the other pidl contents
203 if (threadParams
->offset7C
)
205 memcpy(target
, threadParams
->offset7C
, pidlSize7C
);
206 target
+= pidlSize7C
;
207 hnfData
->pidlSize7C
= pidlSize7C
;
210 // copy the third pidl
211 if (threadParams
->offset84
& 0x8000)
213 *(LPITEMIDLIST
*) target
= pidl80
;
214 target
+= pidlSize80
;
215 hnfData
->pidlSize80
= pidlSize80
;
219 memcpy(target
, pidl80
, pidlSize80
);
220 target
+= pidlSize80
;
221 hnfData
->pidlSize80
= pidlSize80
;
224 // and finally the path string
227 memcpy(target
, strPath
, pathLength
);
228 hnfData
->pathLength
= pathLength
;
231 SHUnlockShared(hnfData
);
236 PIE_THREAD_PARAM_BLOCK
ParseSharedPacket(HANDLE hData
)
241 PIE_THREAD_PARAM_BLOCK params
= NULL
;
246 pid
= GetCurrentProcessId();
247 block
= (PBYTE
) SHLockShared(hData
, pid
);
249 hnfData
= (HNFBlock
*) block
;
253 if (hnfData
->cbSize
< sizeof(HNFBlock
))
256 params
= SHCreateIETHREADPARAM(0, hnfData
->offset8
, 0, 0);
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
;
273 block
+= sizeof(*hnfData
);
274 if (hnfData
->directoryPidlLength
)
276 LPITEMIDLIST pidl
= NULL
;
278 pidl
= ILClone((LPITEMIDLIST
) block
);
279 params
->directoryPIDL
= pidl
;
281 block
+= hnfData
->directoryPidlLength
;
284 if (hnfData
->pidlSize7C
)
286 LPITEMIDLIST pidl
= NULL
;
288 pidl
= ILClone((LPITEMIDLIST
) block
);
289 params
->offset7C
= pidl
;
291 block
+= hnfData
->pidlSize80
;
294 if (hnfData
->pidlSize80
)
296 if (!(params
->offset84
& 0x8000))
298 params
->offset80
= *(LPITEMIDLIST
*) block
;
302 LPITEMIDLIST pidl
= NULL
;
304 pidl
= ILClone((LPITEMIDLIST
) block
);
305 params
->offset80
= pidl
;
308 block
+= hnfData
->pidlSize80
;
311 if (hnfData
->pathLength
)
313 CComPtr
<IShellFolder
> psfDesktop
;
314 PWSTR strPath
= (PWSTR
) block
;
316 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
318 params
->directoryPIDL
= NULL
;
322 if (FAILED(psfDesktop
->ParseDisplayName(NULL
, NULL
, strPath
, NULL
, ¶ms
->directoryPIDL
, NULL
)))
324 params
->directoryPIDL
= NULL
;
330 SHUnlockShared(hnfData
);
331 SHFreeShared(hData
, pid
);
334 if (!params
->directoryPIDL
)
336 SHDestroyIETHREADPARAM(params
);
344 static HRESULT
ExplorerMessageLoop(IEThreadParamBlock
* parameters
)
350 // Tell the thread ref we are using it.
351 if (parameters
&& parameters
->offsetF8
)
352 parameters
->offsetF8
->AddRef();
354 /* Handle /e parameter */
356 if ((parameters
->dwFlags
& SH_EXPLORER_CMDLINE_FLAG_E
))
357 wFlags
|= SBSP_EXPLOREMODE
;
359 /* Handle /select parameter */
360 PUITEMID_CHILD pidlSelect
= NULL
;
361 if ((parameters
->dwFlags
& SH_EXPLORER_CMDLINE_FLAG_SELECT
) &&
362 (ILGetNext(parameters
->directoryPIDL
) != NULL
))
364 pidlSelect
= ILClone(ILFindLastID(parameters
->directoryPIDL
));
365 ILRemoveLastID(parameters
->directoryPIDL
);
368 CComPtr
<IShellBrowser
> psb
;
369 hResult
= CShellBrowser_CreateInstance(IID_PPV_ARG(IShellBrowser
, &psb
));
370 if (FAILED_UNEXPECTEDLY(hResult
))
373 hResult
= psb
->BrowseObject(parameters
->directoryPIDL
, wFlags
);
374 if (FAILED_UNEXPECTEDLY(hResult
))
377 if (pidlSelect
!= NULL
)
379 CComPtr
<IShellView
> shellView
;
380 hResult
= psb
->QueryActiveShellView(&shellView
);
381 if (SUCCEEDED(hResult
))
383 shellView
->SelectItem(pidlSelect
, SVSI_SELECT
|SVSI_ENSUREVISIBLE
);
388 CComPtr
<IBrowserService2
> browser
;
389 hResult
= psb
->QueryInterface(IID_PPV_ARG(IBrowserService2
, &browser
));
390 if (FAILED_UNEXPECTEDLY(hResult
))
395 while ((Ret
= GetMessage(&Msg
, NULL
, 0, 0)) != 0)
399 // Error: continue or exit?
403 if (Msg
.message
== WM_QUIT
)
406 if (browser
->v_MayTranslateAccelerator(&Msg
) != S_OK
)
408 TranslateMessage(&Msg
);
409 DispatchMessage(&Msg
);
413 int nrc
= browser
->Release();
416 DbgPrint("WARNING: There are %d references to the CShellBrowser active or leaked.\n", nrc
);
421 // Tell the thread ref we are not using it anymore.
422 if (parameters
&& parameters
->offsetF8
)
423 parameters
->offsetF8
->Release();
428 static DWORD WINAPI
BrowserThreadProc(LPVOID lpThreadParameter
)
430 IEThreadParamBlock
* parameters
= (IEThreadParamBlock
*) lpThreadParameter
;
433 ExplorerMessageLoop(parameters
);
435 /* Destroying the parameters releases the thread reference */
436 SHDestroyIETHREADPARAM(parameters
);
438 /* Wake up the proxy desktop thread so it can check whether the last browser thread exited */
439 /* Use PostMessage in order to force GetMessage to return and check if all browser windows have exited */
440 PostMessageW(FindShellProxy(NULL
), WM_EXPLORER_1037
, 0, 0);
447 /*************************************************************************
448 * SHCreateIETHREADPARAM [BROWSEUI.123]
450 extern "C" IEThreadParamBlock
*WINAPI
SHCreateIETHREADPARAM(
451 long param8
, long paramC
, IUnknown
*param10
, IUnknown
*param14
)
453 IEThreadParamBlock
*result
;
455 TRACE("SHCreateIETHREADPARAM\n");
457 result
= (IEThreadParamBlock
*) LocalAlloc(LMEM_ZEROINIT
, 256);
460 result
->offset0
= param8
;
461 result
->offset8
= paramC
;
462 result
->offsetC
= param10
;
465 result
->offset14
= param14
;
471 /*************************************************************************
472 * SHCloneIETHREADPARAM [BROWSEUI.124]
474 extern "C" IEThreadParamBlock
*WINAPI
SHCloneIETHREADPARAM(IEThreadParamBlock
*param
)
476 IEThreadParamBlock
*result
;
478 TRACE("SHCloneIETHREADPARAM\n");
480 result
= (IEThreadParamBlock
*) LocalAlloc(LMEM_FIXED
, 256);
483 memcpy(result
, param
, 0x40 * 4);
484 if (result
->directoryPIDL
!= NULL
)
485 result
->directoryPIDL
= ILClone(result
->directoryPIDL
);
486 if (result
->offset7C
!= NULL
)
487 result
->offset7C
= ILClone(result
->offset7C
);
488 if (result
->offset80
!= NULL
)
489 result
->offset80
= ILClone(result
->offset80
);
490 if (result
->offset70
!= NULL
)
491 result
->offset70
->AddRef();
493 if (result
->offsetC
!= NULL
)
494 result
->offsetC
->Method2C();
499 /*************************************************************************
500 * SHDestroyIETHREADPARAM [BROWSEUI.126]
502 extern "C" void WINAPI
SHDestroyIETHREADPARAM(IEThreadParamBlock
*param
)
504 TRACE("SHDestroyIETHREADPARAM\n");
508 if (param
->directoryPIDL
!= NULL
)
509 ILFree(param
->directoryPIDL
);
510 if (param
->offset7C
!= NULL
)
511 ILFree(param
->offset7C
);
512 if ((param
->dwFlags
& 0x80000) == 0 && param
->offset80
!= NULL
)
513 ILFree(param
->offset80
);
514 if (param
->offset14
!= NULL
)
515 param
->offset14
->Release();
516 if (param
->offset70
!= NULL
)
517 param
->offset70
->Release();
518 if (param
->offset78
!= NULL
)
519 param
->offset78
->Release();
520 if (param
->offsetC
!= NULL
)
521 param
->offsetC
->Release();
522 if (param
->offsetF8
!= NULL
)
523 param
->offsetF8
->Release();
527 /*************************************************************************
528 * SHOnCWMCommandLine [BROWSEUI.127]
530 extern "C" BOOL WINAPI
SHOnCWMCommandLine(HANDLE hSharedInfo
)
532 TRACE("SHOnCWMCommandLine\n");
534 PIE_THREAD_PARAM_BLOCK params
= ParseSharedPacket(hSharedInfo
);
537 return SHOpenFolderWindow(params
);
539 SHDestroyIETHREADPARAM(params
);
544 /*************************************************************************
545 * SHOpenFolderWindow [BROWSEUI.102]
546 * see SHOpenNewFrame below for remarks
548 extern "C" HRESULT WINAPI
SHOpenFolderWindow(PIE_THREAD_PARAM_BLOCK parameters
)
553 WCHAR debugStr
[MAX_PATH
+ 1];
554 SHGetPathFromIDListW(parameters
->directoryPIDL
, debugStr
);
556 TRACE("SHOpenFolderWindow %p(%S)\n", parameters
->directoryPIDL
, debugStr
);
558 PIE_THREAD_PARAM_BLOCK paramsCopy
= SHCloneIETHREADPARAM(parameters
);
560 SHGetInstanceExplorer(&(paramsCopy
->offsetF8
));
561 threadHandle
= CreateThread(NULL
, 0x10000, BrowserThreadProc
, paramsCopy
, 0, &threadID
);
562 if (threadHandle
!= NULL
)
564 CloseHandle(threadHandle
);
567 SHDestroyIETHREADPARAM(paramsCopy
);
573 // this function should handle creating a new process if needed, but I'm leaving that out for now
574 // this function always opens a new window - it does NOT check for duplicates
575 /*************************************************************************
576 * SHOpenNewFrame [BROWSEUI.103]
578 extern "C" HRESULT WINAPI
SHOpenNewFrame(LPITEMIDLIST pidl
, IUnknown
*paramC
, long param10
, DWORD dwFlags
)
580 IEThreadParamBlock
*parameters
;
582 TRACE("SHOpenNewFrame\n");
584 parameters
= SHCreateIETHREADPARAM(0, 1, paramC
, NULL
);
585 if (parameters
== NULL
)
588 return E_OUTOFMEMORY
;
591 parameters
->offset10
= param10
;
592 parameters
->directoryPIDL
= pidl
;
593 parameters
->dwFlags
= dwFlags
;
595 HRESULT hr
= SHOpenFolderWindow(parameters
);
597 SHDestroyIETHREADPARAM(parameters
);
602 /*************************************************************************
603 * SHCreateFromDesktop [BROWSEUI.106]
604 * parameter is a FolderInfo
606 BOOL WINAPI
SHCreateFromDesktop(ExplorerCommandLineParseResults
* parseResults
)
608 TRACE("SHCreateFromDesktop\n");
610 IEThreadParamBlock
* parameters
= SHCreateIETHREADPARAM(0, 0, 0, 0);
614 PCWSTR strPath
= NULL
;
615 if (parseResults
->dwFlags
& SH_EXPLORER_CMDLINE_FLAG_STRING
)
617 if (parseResults
->pidlPath
)
619 WARN("strPath and pidlPath are both assigned. This shouldn't happen.\n");
622 strPath
= parseResults
->strPath
;
625 parameters
->dwFlags
= parseResults
->dwFlags
;
626 parameters
->offset8
= parseResults
->nCmdShow
;
628 LPITEMIDLIST pidl
= parseResults
->pidlPath
? ILClone(parseResults
->pidlPath
) : NULL
;
629 if (!pidl
&& parseResults
->dwFlags
& SH_EXPLORER_CMDLINE_FLAG_STRING
)
631 if (parseResults
->strPath
&& parseResults
->strPath
[0])
633 pidl
= ILCreateFromPathW(parseResults
->strPath
);
637 // HACK! This shouldn't happen! SHExplorerParseCmdLine needs fixing.
640 SHGetFolderLocation(NULL
, CSIDL_PERSONAL
, NULL
, NULL
, &pidl
);
643 parameters
->directoryPIDL
= pidl
;
645 // Try to find the owner of the idlist, if we aren't running /SEPARATE
647 if (!(parseResults
->dwFlags
& SH_EXPLORER_CMDLINE_FLAG_SEPARATE
))
648 desktop
= FindShellProxy(parameters
->directoryPIDL
);
650 // If found, ask it to open the new window
653 TRACE("Found desktop hwnd=%p\n", desktop
);
657 GetWindowThreadProcessId(desktop
, &dwProcessId
);
658 AllowSetForegroundWindow(dwProcessId
);
660 HANDLE hShared
= MakeSharedPacket(parameters
, strPath
, dwProcessId
);
663 TRACE("Sending open message...\n");
665 PostMessageW(desktop
, WM_EXPLORER_OPEN_NEW_WINDOW
, 0, (LPARAM
) hShared
);
668 SHDestroyIETHREADPARAM(parameters
);
672 TRACE("Desktop not found or separate flag requested.\n");
674 // Else, start our own message loop!
675 HRESULT hr
= CoInitialize(NULL
);
676 CProxyDesktop
* proxy
= new CProxyDesktop(parameters
);
679 g_hwndProxyDesktop
= proxy
->Create(0);
682 CComPtr
<IUnknown
> thread
;
683 if (SHCreateThreadRef(&refCount
, &thread
) >= 0)
685 SHSetInstanceExplorer(thread
);
687 parameters
->directoryPIDL
= ILCreateFromPath(strPath
);
688 SHOpenFolderWindow(parameters
);
694 while (GetMessageW(&Msg
, 0, 0, 0) && refCount
)
696 TranslateMessage(&Msg
);
697 DispatchMessageW(&Msg
);
700 DestroyWindow(g_hwndProxyDesktop
);
708 SHDestroyIETHREADPARAM(parameters
);