5353#include " nsThreadUtils.h"
5454#include " nsXULAppAPI.h"
5555
56+ #include " nsIWindowMediator.h"
57+ #include " mozIDOMWindow.h"
58+ #include " nsPIDOMWindow.h"
59+ #include " nsIWidget.h"
60+ #include " mozilla/WidgetUtils.h"
61+
5662using namespace mozilla ;
5763
5864#define CHECK_mWorkingPath () \
@@ -74,9 +80,36 @@ using namespace mozilla;
7480#define DRIVE_REMOTE 4
7581#endif
7682
83+ static HWND
84+ GetMostRecentNavigatorHWND ()
85+ {
86+ nsresult rv;
87+ nsCOMPtr<nsIWindowMediator> winMediator (
88+ do_GetService (NS_WINDOWMEDIATOR_CONTRACTID , &rv));
89+ if (NS_FAILED (rv)) {
90+ return nullptr ;
91+ }
92+
93+ nsCOMPtr<mozIDOMWindowProxy> navWin;
94+ rv = winMediator->GetMostRecentWindow (MOZ_UTF16 (" navigator:browser" ),
95+ getter_AddRefs (navWin));
96+ if (NS_FAILED (rv) || !navWin) {
97+ return nullptr ;
98+ }
99+
100+ nsPIDOMWindowOuter* win = nsPIDOMWindowOuter::From (navWin);
101+ nsCOMPtr<nsIWidget> widget = widget::WidgetUtils::DOMWindowToWidget (win);
102+ if (!widget) {
103+ return nullptr ;
104+ }
105+
106+ return reinterpret_cast <HWND >(widget->GetNativeData (NS_NATIVE_WINDOW ));
107+ }
108+
109+
77110/* *
78111 * A runnable to dispatch back to the main thread when
79- * AsyncLocalFileWinOperation completes.
112+ * AsyncRevealOperation completes.
80113*/
81114class AsyncLocalFileWinDone : public Runnable
82115{
@@ -107,37 +140,28 @@ class AsyncLocalFileWinDone : public Runnable
107140 * A runnable to dispatch from the main thread when an async operation should
108141 * be performed.
109142*/
110- class AsyncLocalFileWinOperation : public Runnable
143+ class AsyncRevealOperation : public Runnable
111144{
112145public:
113- enum FileOp { RevealOp, LaunchOp };
114-
115- AsyncLocalFileWinOperation (AsyncLocalFileWinOperation::FileOp aOperation,
116- const nsAString& aResolvedPath) :
117- mOperation (aOperation),
118- mResolvedPath (aResolvedPath)
146+ explicit AsyncRevealOperation (const nsAString& aResolvedPath)
147+ : mResolvedPath(aResolvedPath)
119148 {
120149 }
121150
122151 NS_IMETHOD Run ()
123152 {
124153 MOZ_ASSERT (!NS_IsMainThread(),
125- " AsyncLocalFileWinOperation should not be run on the main thread!" );
154+ " AsyncRevealOperation should not be run on the main thread!" );
126155
127- CoInitialize (nullptr );
128- switch (mOperation ) {
129- case RevealOp: {
130- Reveal ();
131- }
132- break ;
133- case LaunchOp: {
134- Launch ();
135- }
136- break ;
156+ bool doCoUninitialize = SUCCEEDED (
157+ CoInitializeEx (nullptr , COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE ));
158+ Reveal ();
159+ if (doCoUninitialize) {
160+ CoUninitialize ();
137161 }
138- CoUninitialize ();
139162
140- // Send the result back to the main thread so that it can shutdown
163+ // Send the result back to the main thread so that this thread can be
164+ // cleanly shut down
141165 nsCOMPtr<nsIRunnable> resultrunnable = new AsyncLocalFileWinDone ();
142166 NS_DispatchToMainThread (resultrunnable);
143167 return NS_OK ;
@@ -206,82 +230,6 @@ class AsyncLocalFileWinOperation : public Runnable
206230 return SUCCEEDED (hr) ? NS_OK : NS_ERROR_FAILURE ;
207231 }
208232
209- // Launches the default shell operation for the file path
210- nsresult Launch ()
211- {
212- // use the app registry name to launch a shell execute....
213- SHELLEXECUTEINFOW seinfo;
214- memset (&seinfo, 0 , sizeof (seinfo));
215- seinfo.cbSize = sizeof (SHELLEXECUTEINFOW );
216- seinfo.hwnd = nullptr ;
217- seinfo.lpVerb = nullptr ;
218- seinfo.lpFile = mResolvedPath .get ();
219- seinfo.lpParameters = nullptr ;
220- seinfo.lpDirectory = nullptr ;
221- seinfo.nShow = SW_SHOWNORMAL ;
222-
223- // Use the directory of the file we're launching as the working
224- // directory. That way if we have a self extracting EXE it won't
225- // suggest to extract to the install directory.
226- WCHAR workingDirectory[MAX_PATH + 1 ] = { L' \0 ' };
227- wcsncpy (workingDirectory, mResolvedPath .get (), MAX_PATH );
228- if (PathRemoveFileSpecW (workingDirectory)) {
229- seinfo.lpDirectory = workingDirectory;
230- } else {
231- NS_WARNING (" Could not set working directory for launched file." );
232- }
233-
234- if (ShellExecuteExW (&seinfo)) {
235- return NS_OK ;
236- }
237- DWORD r = GetLastError ();
238- // if the file has no association, we launch windows'
239- // "what do you want to do" dialog
240- if (r == SE_ERR_NOASSOC ) {
241- nsAutoString shellArg;
242- shellArg.AssignLiteral (MOZ_UTF16 (" shell32.dll,OpenAs_RunDLL " ));
243- shellArg.Append (mResolvedPath );
244- seinfo.lpFile = L" RUNDLL32.EXE" ;
245- seinfo.lpParameters = shellArg.get ();
246- if (ShellExecuteExW (&seinfo)) {
247- return NS_OK ;
248- }
249- r = GetLastError ();
250- }
251- if (r < 32 ) {
252- switch (r) {
253- case 0 :
254- case SE_ERR_OOM :
255- return NS_ERROR_OUT_OF_MEMORY ;
256- case ERROR_FILE_NOT_FOUND :
257- return NS_ERROR_FILE_NOT_FOUND ;
258- case ERROR_PATH_NOT_FOUND :
259- return NS_ERROR_FILE_UNRECOGNIZED_PATH ;
260- case ERROR_BAD_FORMAT :
261- return NS_ERROR_FILE_CORRUPTED ;
262- case SE_ERR_ACCESSDENIED :
263- return NS_ERROR_FILE_ACCESS_DENIED ;
264- case SE_ERR_ASSOCINCOMPLETE :
265- case SE_ERR_NOASSOC :
266- return NS_ERROR_UNEXPECTED ;
267- case SE_ERR_DDEBUSY :
268- case SE_ERR_DDEFAIL :
269- case SE_ERR_DDETIMEOUT :
270- return NS_ERROR_NOT_AVAILABLE ;
271- case SE_ERR_DLLNOTFOUND :
272- return NS_ERROR_FAILURE ;
273- case SE_ERR_SHARE :
274- return NS_ERROR_FILE_IS_LOCKED ;
275- default :
276- return NS_ERROR_FILE_EXECUTION_FAILED ;
277- }
278- }
279- return NS_OK ;
280- }
281-
282- // Stores the operation that will be performed on the thread
283- AsyncLocalFileWinOperation::FileOp mOperation ;
284-
285233 // Stores the path to perform the operation on
286234 nsString mResolvedPath ;
287235};
@@ -3313,9 +3261,7 @@ nsLocalFile::Reveal()
33133261 return rv;
33143262 }
33153263
3316- nsCOMPtr<nsIRunnable> runnable =
3317- new AsyncLocalFileWinOperation (AsyncLocalFileWinOperation::RevealOp,
3318- mResolvedPath );
3264+ nsCOMPtr<nsIRunnable> runnable = new AsyncRevealOperation (mResolvedPath );
33193265
33203266 // After the dispatch, the result runnable will shut down the worker
33213267 // thread, so we can let it go.
@@ -3335,21 +3281,74 @@ nsLocalFile::Launch()
33353281 return rv;
33363282 }
33373283
3338- // To create a new thread, get the thread manager
3339- nsCOMPtr<nsIThreadManager> tm = do_GetService (NS_THREADMANAGER_CONTRACTID );
3340- nsCOMPtr<nsIThread> mythread;
3341- rv = tm->NewThread (0 , 0 , getter_AddRefs (mythread));
3342- if (NS_FAILED (rv)) {
3343- return rv;
3284+ // use the app registry name to launch a shell execute....
3285+ SHELLEXECUTEINFOW seinfo;
3286+ memset (&seinfo, 0 , sizeof (seinfo));
3287+ seinfo.cbSize = sizeof (SHELLEXECUTEINFOW );
3288+ seinfo.fMask = SEE_MASK_ASYNCOK ;
3289+ seinfo.hwnd = GetMostRecentNavigatorHWND ();
3290+ seinfo.lpVerb = nullptr ;
3291+ seinfo.lpFile = mResolvedPath .get ();
3292+ seinfo.lpParameters = nullptr ;
3293+ seinfo.lpDirectory = nullptr ;
3294+ seinfo.nShow = SW_SHOWNORMAL ;
3295+
3296+ // Use the directory of the file we're launching as the working
3297+ // directory. That way if we have a self extracting EXE it won't
3298+ // suggest to extract to the install directory.
3299+ WCHAR workingDirectory[MAX_PATH + 1 ] = { L' \0 ' };
3300+ wcsncpy (workingDirectory, mResolvedPath .get (), MAX_PATH );
3301+ if (PathRemoveFileSpecW (workingDirectory)) {
3302+ seinfo.lpDirectory = workingDirectory;
3303+ } else {
3304+ NS_WARNING (" Could not set working directory for launched file." );
33443305 }
33453306
3346- nsCOMPtr<nsIRunnable> runnable =
3347- new AsyncLocalFileWinOperation (AsyncLocalFileWinOperation::LaunchOp,
3348- mResolvedPath );
3349-
3350- // After the dispatch, the result runnable will shut down the worker
3351- // thread, so we can let it go.
3352- mythread->Dispatch (runnable, NS_DISPATCH_NORMAL );
3307+ if (ShellExecuteExW (&seinfo)) {
3308+ return NS_OK ;
3309+ }
3310+ DWORD r = GetLastError ();
3311+ // if the file has no association, we launch windows'
3312+ // "what do you want to do" dialog
3313+ if (r == SE_ERR_NOASSOC ) {
3314+ nsAutoString shellArg;
3315+ shellArg.AssignLiteral (MOZ_UTF16 (" shell32.dll,OpenAs_RunDLL " ));
3316+ shellArg.Append (mResolvedPath );
3317+ seinfo.lpFile = L" RUNDLL32.EXE" ;
3318+ seinfo.lpParameters = shellArg.get ();
3319+ if (ShellExecuteExW (&seinfo)) {
3320+ return NS_OK ;
3321+ }
3322+ r = GetLastError ();
3323+ }
3324+ if (r < 32 ) {
3325+ switch (r) {
3326+ case 0 :
3327+ case SE_ERR_OOM :
3328+ return NS_ERROR_OUT_OF_MEMORY ;
3329+ case ERROR_FILE_NOT_FOUND :
3330+ return NS_ERROR_FILE_NOT_FOUND ;
3331+ case ERROR_PATH_NOT_FOUND :
3332+ return NS_ERROR_FILE_UNRECOGNIZED_PATH ;
3333+ case ERROR_BAD_FORMAT :
3334+ return NS_ERROR_FILE_CORRUPTED ;
3335+ case SE_ERR_ACCESSDENIED :
3336+ return NS_ERROR_FILE_ACCESS_DENIED ;
3337+ case SE_ERR_ASSOCINCOMPLETE :
3338+ case SE_ERR_NOASSOC :
3339+ return NS_ERROR_UNEXPECTED ;
3340+ case SE_ERR_DDEBUSY :
3341+ case SE_ERR_DDEFAIL :
3342+ case SE_ERR_DDETIMEOUT :
3343+ return NS_ERROR_NOT_AVAILABLE ;
3344+ case SE_ERR_DLLNOTFOUND :
3345+ return NS_ERROR_FAILURE ;
3346+ case SE_ERR_SHARE :
3347+ return NS_ERROR_FILE_IS_LOCKED ;
3348+ default :
3349+ return NS_ERROR_FILE_EXECUTION_FAILED ;
3350+ }
3351+ }
33533352 return NS_OK ;
33543353}
33553354
0 commit comments