Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit e7f3517

Browse files
committed
Bug 1518639: Implement windows remoting server and client. r=jimm
Implements the windows remove client and server based on the current remoting code in nsNativeAppSupportWin.cpp. Makes the hidden window classname encode both program name and profile name. nsNativeAppSupportWin is now just used for setting up the console. Differential Revision: https://phabricator.services.mozilla.com/D19076 --HG-- extra : source : 84e8066625fd72fdb1eb6eab85621ae842fe91b4 extra : amend_source : b698f986cce0ccfae29c04fcbe0d84a6c8605ab6
1 parent 449b275 commit e7f3517

File tree

7 files changed

+326
-577
lines changed

7 files changed

+326
-577
lines changed

ipc/glue/WindowsMessageLoop.cpp

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,6 @@ const wchar_t k3rdPartyWindowProp[] = L"Mozilla3rdPartyWindow";
9191
// This isn't defined before Windows XP.
9292
enum { WM_XP_THEMECHANGED = 0x031A };
9393

94-
char16_t gAppMessageWindowName[256] = {0};
95-
int32_t gAppMessageWindowNameLength = 0;
96-
9794
nsTArray<HWND>* gNeuteredWindows = nullptr;
9895

9996
typedef nsTArray<nsAutoPtr<DeferredMessage> > DeferredMessageArray;
@@ -474,34 +471,6 @@ static bool WindowIsDeferredWindow(HWND hWnd) {
474471
return true;
475472
}
476473

477-
// nsNativeAppSupport makes a window like "FirefoxMessageWindow" based on the
478-
// toolkit app's name. It's pretty expensive to calculate this so we only try
479-
// once.
480-
if (gAppMessageWindowNameLength == 0) {
481-
nsCOMPtr<nsIXULAppInfo> appInfo =
482-
do_GetService("@mozilla.org/xre/app-info;1");
483-
if (appInfo) {
484-
nsAutoCString appName;
485-
if (NS_SUCCEEDED(appInfo->GetName(appName))) {
486-
appName.AppendLiteral("MessageWindow");
487-
nsDependentString windowName(gAppMessageWindowName);
488-
CopyUTF8toUTF16(appName, windowName);
489-
gAppMessageWindowNameLength = windowName.Length();
490-
}
491-
}
492-
493-
// Don't try again if that failed.
494-
if (gAppMessageWindowNameLength == 0) {
495-
gAppMessageWindowNameLength = -1;
496-
}
497-
}
498-
499-
if (gAppMessageWindowNameLength != -1 &&
500-
className.Equals(nsDependentString(gAppMessageWindowName,
501-
gAppMessageWindowNameLength))) {
502-
return true;
503-
}
504-
505474
return false;
506475
}
507476

toolkit/components/remote/nsWinRemoteClient.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
77

88
#include "nsWinRemoteClient.h"
9+
#include "nsWinRemoteUtils.h"
10+
11+
#include <windows.h>
12+
13+
using namespace mozilla;
914

1015
nsresult nsWinRemoteClient::Init() {
1116
return NS_OK;
@@ -16,5 +21,37 @@ nsresult nsWinRemoteClient::SendCommandLine(const char *aProgram, const char *aP
1621
const char *aDesktopStartupID,
1722
char **aResponse, bool *aSucceeded) {
1823
*aSucceeded = false;
24+
25+
nsString className;
26+
BuildClassName(aProgram, aProfile, className);
27+
28+
HWND handle = ::FindWindowW(className.get(), 0);
29+
30+
if (!handle) {
31+
return NS_OK;
32+
}
33+
34+
WCHAR *cmd = ::GetCommandLineW();
35+
WCHAR cwd[MAX_PATH];
36+
_wgetcwd(cwd, MAX_PATH);
37+
38+
// Construct a narrow UTF8 buffer <commandline>\0<workingdir>\0
39+
NS_ConvertUTF16toUTF8 utf8buffer(cmd);
40+
utf8buffer.Append('\0');
41+
WCHAR *cwdPtr = cwd;
42+
AppendUTF16toUTF8(MakeStringSpan(reinterpret_cast<char16_t *>(cwdPtr)),
43+
utf8buffer);
44+
utf8buffer.Append('\0');
45+
46+
// We used to set dwData to zero, when we didn't send the working dir.
47+
// Now we're using it as a version number.
48+
COPYDATASTRUCT cds = {1, utf8buffer.Length(), (void *)utf8buffer.get()};
49+
// Bring the already running Mozilla process to the foreground.
50+
// nsWindow will restore the window (if minimized) and raise it.
51+
::SetForegroundWindow(handle);
52+
::SendMessage(handle, WM_COPYDATA, 0, (LPARAM)&cds);
53+
54+
*aSucceeded = true;
55+
1956
return NS_OK;
2057
}

toolkit/components/remote/nsWinRemoteServer.cpp

Lines changed: 256 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,266 @@
66
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
77

88
#include "nsWinRemoteServer.h"
9+
#include "nsWinRemoteUtils.h"
10+
#include "nsCOMPtr.h"
11+
#include "nsIComponentManager.h"
12+
#include "nsIServiceManager.h"
13+
#include "nsIDOMChromeWindow.h"
14+
#include "nsXPCOM.h"
15+
#include "nsPIDOMWindow.h"
16+
#include "nsIWindowMediator.h"
17+
#include "nsIBaseWindow.h"
18+
#include "nsIWidget.h"
19+
#include "nsICommandLineRunner.h"
20+
#include "nsICommandLine.h"
21+
#include "nsCommandLine.h"
22+
#include "nsIDocShell.h"
23+
24+
HWND hwndForDOMWindow(mozIDOMWindowProxy *window) {
25+
if (!window) {
26+
return 0;
27+
}
28+
nsCOMPtr<nsPIDOMWindowOuter> pidomwindow = nsPIDOMWindowOuter::From(window);
29+
30+
nsCOMPtr<nsIBaseWindow> ppBaseWindow =
31+
do_QueryInterface(pidomwindow->GetDocShell());
32+
if (!ppBaseWindow) {
33+
return 0;
34+
}
35+
36+
nsCOMPtr<nsIWidget> ppWidget;
37+
ppBaseWindow->GetMainWidget(getter_AddRefs(ppWidget));
38+
39+
return (HWND)(ppWidget->GetNativeData(NS_NATIVE_WIDGET));
40+
}
41+
42+
static nsresult GetMostRecentWindow(mozIDOMWindowProxy **aWindow) {
43+
nsresult rv;
44+
nsCOMPtr<nsIWindowMediator> med(
45+
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv));
46+
if (NS_FAILED(rv)) return rv;
47+
48+
if (med) return med->GetMostRecentWindow(nullptr, aWindow);
49+
50+
return NS_ERROR_FAILURE;
51+
}
52+
53+
void HandleCommandLine(const char *aCmdLineString, nsIFile *aWorkingDir,
54+
uint32_t aState) {
55+
nsresult rv;
56+
57+
int justCounting = 1;
58+
char **argv = 0;
59+
// Flags, etc.
60+
int init = 1;
61+
int between, quoted, bSlashCount;
62+
int argc;
63+
const char *p;
64+
nsAutoCString arg;
65+
66+
nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
67+
68+
// Parse command line args according to MS spec
69+
// (see "Parsing C++ Command-Line Arguments" at
70+
// http://msdn.microsoft.com/library/devprods/vs6/visualc/vclang/_pluslang_parsing_c.2b2b_.command.2d.line_arguments.htm).
71+
// We loop if we've not finished the second pass through.
72+
while (1) {
73+
// Initialize if required.
74+
if (init) {
75+
p = aCmdLineString;
76+
between = 1;
77+
argc = quoted = bSlashCount = 0;
78+
79+
init = 0;
80+
}
81+
if (between) {
82+
// We are traversing whitespace between args.
83+
// Check for start of next arg.
84+
if (*p != 0 && !isspace(*p)) {
85+
// Start of another arg.
86+
between = 0;
87+
arg = "";
88+
switch (*p) {
89+
case '\\':
90+
// Count the backslash.
91+
bSlashCount = 1;
92+
break;
93+
case '"':
94+
// Remember we're inside quotes.
95+
quoted = 1;
96+
break;
97+
default:
98+
// Add character to arg.
99+
arg += *p;
100+
break;
101+
}
102+
} else {
103+
// Another space between args, ignore it.
104+
}
105+
} else {
106+
// We are processing the contents of an argument.
107+
// Check for whitespace or end.
108+
if (*p == 0 || (!quoted && isspace(*p))) {
109+
// Process pending backslashes (interpret them
110+
// literally since they're not followed by a ").
111+
while (bSlashCount) {
112+
arg += '\\';
113+
bSlashCount--;
114+
}
115+
// End current arg.
116+
if (!justCounting) {
117+
argv[argc] = new char[arg.Length() + 1];
118+
strcpy(argv[argc], arg.get());
119+
}
120+
argc++;
121+
// We're now between args.
122+
between = 1;
123+
} else {
124+
// Still inside argument, process the character.
125+
switch (*p) {
126+
case '"':
127+
// First, digest preceding backslashes (if any).
128+
while (bSlashCount > 1) {
129+
// Put one backsplash in arg for each pair.
130+
arg += '\\';
131+
bSlashCount -= 2;
132+
}
133+
if (bSlashCount) {
134+
// Quote is literal.
135+
arg += '"';
136+
bSlashCount = 0;
137+
} else {
138+
// Quote starts or ends a quoted section.
139+
if (quoted) {
140+
// Check for special case of consecutive double
141+
// quotes inside a quoted section.
142+
if (*(p + 1) == '"') {
143+
// This implies a literal double-quote. Fake that
144+
// out by causing next double-quote to look as
145+
// if it was preceded by a backslash.
146+
bSlashCount = 1;
147+
} else {
148+
quoted = 0;
149+
}
150+
} else {
151+
quoted = 1;
152+
}
153+
}
154+
break;
155+
case '\\':
156+
// Add to count.
157+
bSlashCount++;
158+
break;
159+
default:
160+
// Accept any preceding backslashes literally.
161+
while (bSlashCount) {
162+
arg += '\\';
163+
bSlashCount--;
164+
}
165+
// Just add next char to the current arg.
166+
arg += *p;
167+
break;
168+
}
169+
}
170+
}
171+
// Check for end of input.
172+
if (*p) {
173+
// Go to next character.
174+
p++;
175+
} else {
176+
// If on first pass, go on to second.
177+
if (justCounting) {
178+
// Allocate argv array.
179+
argv = new char *[argc];
180+
181+
// Start second pass
182+
justCounting = 0;
183+
init = 1;
184+
} else {
185+
// Quit.
186+
break;
187+
}
188+
}
189+
}
190+
191+
rv = cmdLine->Init(argc, argv, aWorkingDir, aState);
192+
193+
// Cleanup.
194+
while (argc) {
195+
delete[] argv[--argc];
196+
}
197+
delete[] argv;
198+
199+
if (NS_FAILED(rv)) {
200+
NS_ERROR("Error initializing command line.");
201+
return;
202+
}
203+
204+
cmdLine->Run();
205+
}
206+
207+
LRESULT CALLBACK WindowProc(HWND msgWindow, UINT msg, WPARAM wp, LPARAM lp) {
208+
if (msg == WM_COPYDATA) {
209+
// This is an incoming request.
210+
COPYDATASTRUCT *cds = (COPYDATASTRUCT *)lp;
211+
nsCOMPtr<nsIFile> workingDir;
212+
213+
if (1 >= cds->dwData) {
214+
char *wdpath = (char *)cds->lpData;
215+
// skip the command line, and get the working dir of the
216+
// other process, which is after the first null char
217+
while (*wdpath) ++wdpath;
218+
219+
++wdpath;
220+
221+
NS_NewLocalFile(NS_ConvertUTF8toUTF16(wdpath), false,
222+
getter_AddRefs(workingDir));
223+
}
224+
HandleCommandLine((char *)cds->lpData, workingDir,
225+
nsICommandLine::STATE_REMOTE_AUTO);
226+
227+
// Get current window and return its window handle.
228+
nsCOMPtr<mozIDOMWindowProxy> win;
229+
GetMostRecentWindow(getter_AddRefs(win));
230+
return win ? (LRESULT)hwndForDOMWindow(win) : 0;
231+
}
232+
return DefWindowProc(msgWindow, msg, wp, lp);
233+
}
9234

10235
nsresult nsWinRemoteServer::Startup(const char* aAppName,
11236
const char* aProfileName) {
12-
return NS_OK;
237+
238+
nsString className;
239+
BuildClassName(aAppName, aProfileName, className);
240+
241+
WNDCLASSW classStruct = {0, // style
242+
&WindowProc, // lpfnWndProc
243+
0, // cbClsExtra
244+
0, // cbWndExtra
245+
0, // hInstance
246+
0, // hIcon
247+
0, // hCursor
248+
0, // hbrBackground
249+
0, // lpszMenuName
250+
className.get()}; // lpszClassName
251+
252+
// Register the window class.
253+
NS_ENSURE_TRUE(::RegisterClassW(&classStruct), NS_ERROR_FAILURE);
254+
255+
// Create the window.
256+
mHandle = ::CreateWindowW(className.get(),
257+
0, // title
258+
WS_CAPTION, // style
259+
0, 0, 0, 0, // x, y, cx, cy
260+
0, // parent
261+
0, // menu
262+
0, // instance
263+
0); // create struct
264+
265+
return mHandle ? NS_OK : NS_ERROR_FAILURE;
13266
}
14267

15268
void nsWinRemoteServer::Shutdown() {
269+
DestroyWindow(mHandle);
270+
mHandle = nullptr;
16271
}

toolkit/components/remote/nsWinRemoteServer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,18 @@
1010

1111
#include "nsRemoteServer.h"
1212

13+
#include <windows.h>
14+
1315
class nsWinRemoteServer final : public nsRemoteServer {
1416
public:
1517
nsWinRemoteServer() = default;
1618
~nsWinRemoteServer() override = default;
1719

1820
nsresult Startup(const char* aAppName, const char* aProfileName) override;
1921
void Shutdown() override;
22+
23+
private:
24+
HWND mHandle;
2025
};
2126

2227
#endif // __nsWinRemoteService_h__

0 commit comments

Comments
 (0)