OLD | NEW |
---|---|
(Empty) | |
1 /* Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 * Use of this source code is governed by a BSD-style license that can be | |
3 * found in the LICENSE file. | |
4 */ | |
5 | |
6 // This project demonstrates how to migrate a Windows desktop app to Native | |
7 // Client, running first as a Win32 application (define STEP1), then as a PPAPI | |
8 // plugin (define STEP2 through STEP6), and finally as a Native Client module. | |
9 | |
10 // Start with STEP1 defined and the defines for STEP2 through STEP6 commented | |
11 // out. For each step in the process, un-comment the next #define, leaving the | |
12 // previous ones on. Ready, set, port! | |
13 | |
14 // *** SELECT THE WIN32 PLATFORM AND RUN WITH #define STEP1 ONLY *** | |
15 | |
16 #define STEP1 | |
17 // Launches the original Windows desktop application, Hello World, which runs | |
18 // as WinMain. STEP1 encloses Windows-specific functions that are used with | |
19 // the WIN32 and PPAPI platforms. These will be removed when the full PPAPI | |
20 // port is finished (STEP6) | |
21 | |
22 // *** SELECT THE PPAPI PLATFORM *** | |
23 | |
24 #define STEP2 | |
25 | |
26 // Client Module. STEP2 encloses the Native Client module APIs needed to link | |
27 // any app to the browser. The module does nothing except report | |
28 // starting/ending the function Instance_DidCreate. The Windows app does not | |
29 // run because it is not being called. | |
30 | |
31 #define STEP3 | |
32 // What changed: Replace WinMain with WndProc, and call it from | |
33 // Instance_DidCreate, launching hello_nacl_plus in its own window. Since | |
34 // WndProc spins in its message loop, the call to Instance_DidCreate never | |
35 // returns. Close the hello_nacl_plus window and the module initialization will | |
36 // finish. | |
37 | |
38 #define STEP4 | |
39 // What changed: In WndProc replace the message loop with a callback function. | |
40 // Now the app window and the Native Client module are running concurrently. | |
41 | |
42 #define STEP5 | |
43 // What changed: Instance_DidCreate calls initInstanceInBrowserWindow rather | |
44 // than initInstanceInPCWindow. The initInstanceInBrowserWindow uses | |
45 // postMessage to place text (now "Hello, Native Client") in the web page | |
46 // instead of opening and writing to a window. | |
47 | |
48 #define STEP6 | |
49 // What changed: All the Windows code is def'd out, to prove we are | |
50 // PPAPI-compliant. The functional code that is running is the same as STEP5. | |
51 | |
52 // *** SELECT THE NACL64 PLATFORM AND RUN *** | |
53 | |
54 // What changed: The code is the same as STEP6, but you are using the SDK | |
55 // toolchain to compile it into a nexe. The module is now running as a real | |
56 // Native Client executable in a NaCl sandbox, with nacl-gdb attached. | |
57 | |
58 // *** RUN YOUR MODULE IN THE WILD *** | |
59 // You can run your nexe outside of Visual Studio, directly from Chrome by | |
60 // following these steps: | |
61 // - Build STEP6 and verify the file | |
62 // <project directory>/newlib/hello_nacl_plus/hello_nacl_plus.nexe exists | |
63 // - Copy the folder <project directory>/hello_nacl_plus into your NaCl SDK's | |
64 // example directory. | |
65 // - Go to the NaCl SDK directory and launch the httpd.py server. | |
66 // - Launch Chrome, go to about:flags and enable the Native Client flag and | |
67 // relaunch Chrome | |
68 // - Point Chrome at localhost:5103/hello_nacl_plus | |
69 | |
70 #ifdef STEP6 | |
71 // remove Windows-dependent code. | |
72 #undef STEP1 | |
73 #undef STEP3 | |
74 #undef STEP4 | |
75 #define NULL 0 | |
76 #else | |
77 // includes for Windows APIs. | |
78 #include <windows.h> | |
79 #include <stdlib.h> | |
80 #include <tchar.h> | |
81 #endif | |
82 | |
83 #ifdef STEP2 | |
84 // includes for PPAPI C++ | |
85 #include "ppapi/cpp/instance.h" | |
86 #include "ppapi/cpp/module.h" | |
87 #include "ppapi/cpp/var.h" | |
88 #include "ppapi/cpp/core.h" | |
89 #include "ppapi/cpp/completion_callback.h" | |
90 #include "ppapi/utility/completion_callback_factory.h" | |
91 | |
92 // This is a known PPAPI platform problem (Issue 81375). | |
93 // When WinUser.h is included it defines PostMessage, so we undef it here. | |
94 // There is a work-around: | |
95 #ifdef PostMessage | |
96 #undef PostMessage | |
97 #endif | |
98 | |
99 class NaClProjectInstance *myInstance; | |
100 int initInstanceInPCWindow(); | |
binji
2012/10/15 22:15:46
capitalize
Sam Clegg
2012/10/15 22:54:52
Done.
| |
101 void initInstanceInBrowserWindow(); | |
binji
2012/10/15 22:15:46
capitalize
Sam Clegg
2012/10/15 22:54:52
Done.
Sam Clegg
2012/10/15 22:54:52
Done.
| |
102 | |
103 #endif | |
104 | |
105 #ifdef STEP2 | |
106 | |
107 // **** Native Client Framework **** | |
108 | |
109 // The Instance class. | |
110 class NaClProjectInstance : public pp::Instance { | |
111 public: | |
binji
2012/10/15 22:15:46
indent 1 space
Sam Clegg
2012/10/15 22:54:52
Done.
| |
112 pp::CompletionCallbackFactory<NaClProjectInstance> factory_; | |
binji
2012/10/15 22:15:46
data members at end of class
Sam Clegg
2012/10/15 22:54:52
Done.
| |
113 | |
114 explicit NaClProjectInstance(PP_Instance instance) | |
115 : pp::Instance(instance), | |
binji
2012/10/15 22:15:46
indent 4
Sam Clegg
2012/10/15 22:54:52
Done.
| |
116 // Use this macro to eliminate compiler warning. | |
117 PP_ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) { | |
118 myInstance = this; | |
119 } | |
120 | |
121 | |
122 virtual ~NaClProjectInstance() { | |
123 } | |
124 | |
125 virtual bool Init(uint32_t /*argc*/, const char* /*argn*/[], | |
126 const char* /*argv*/[]) { | |
binji
2012/10/15 22:15:46
indent to align with ( from previous line
Sam Clegg
2012/10/15 22:54:52
Done.
| |
127 PostMessage(pp::Var("Creating Instance Start")); | |
128 #ifdef STEP5 | |
129 // Will be included in STEP5 and STEP6 | |
130 // Uses messaging to relay text to the module's view on the web page | |
131 initInstanceInBrowserWindow(); | |
132 #else | |
133 #ifdef STEP3 | |
134 // Will be included in STEP3 and STEP4 only | |
135 // Uses WndProc to place text in a window separate from the browser. | |
136 initInstanceInPCWindow(); | |
137 #endif | |
138 #endif | |
139 PostMessage(pp::Var("Creating Instance End")); | |
140 return true; | |
141 } | |
142 | |
143 #ifdef STEP4 | |
144 // Implements Windows window message loop with a callback function. | |
145 void NaClProjectInstance::SendCallback(int result) { | |
146 pp::Core* core = pp::Module::Get()->core(); | |
147 CompletionCallback callback = factory_.NewCallback(&HandleWindowMsg); | |
148 core->CallOnMainThread(100, callbacl, result); | |
149 } | |
150 | |
151 void HandleWindowMsg(int32_t result) { | |
152 MSG uMsg; | |
153 if (PeekMessage(&uMsg, NULL, 0, 0, PM_REMOVE)) { | |
154 TranslateMessage(&uMsg); | |
155 DispatchMessage(&uMsg); | |
156 } | |
157 SendCallback(0); | |
158 } | |
159 | |
160 #endif | |
161 private: | |
binji
2012/10/15 22:15:46
indent 1 space
Sam Clegg
2012/10/15 22:54:52
Done.
Sam Clegg
2012/10/15 22:54:52
Done.
Sam Clegg
2012/10/15 22:54:52
Done.
| |
162 virtual void HandleMessage(const pp::Var& var_message) { | |
163 } | |
164 }; | |
165 | |
166 // The Module class. | |
167 class NaClProjectModule : public pp::Module { | |
168 public: | |
binji
2012/10/15 22:15:46
indent 1 space
Sam Clegg
2012/10/15 22:54:52
Done.
| |
169 NaClProjectModule() : pp::Module() {} | |
170 virtual ~NaClProjectModule() {} | |
171 | |
172 virtual pp::Instance* CreateInstance(PP_Instance instance) { | |
173 return new NaClProjectInstance(instance); | |
174 } | |
175 }; | |
176 | |
177 namespace pp { | |
178 Module* CreateModule() { | |
binji
2012/10/15 22:15:46
no indent for namespaces
Sam Clegg
2012/10/15 22:54:52
Done.
| |
179 return new NaClProjectModule(); | |
180 } | |
181 } | |
182 | |
183 #endif | |
184 | |
185 // **** Application Code **** | |
186 | |
187 #ifdef STEP1 | |
binji
2012/10/15 22:15:46
same fixes from the C version of this file...?
| |
188 // Desktop Windows Hello World app. Native Client agnostic. | |
189 | |
190 static TCHAR szWindowClass[] = _T("win32app"); | |
191 static TCHAR szTitle[] = _T("hello_nacl_plus"); | |
192 HINSTANCE hInst; | |
193 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); | |
194 | |
195 // WinMain | |
196 int WINAPI WinMain(HINSTANCE hInstance, | |
197 HINSTANCE hPrevInstance, | |
198 LPSTR lpCmdLine, | |
199 int nCmdShow) | |
200 { | |
201 WNDCLASSEX wcex; | |
202 | |
203 wcex.cbSize = sizeof(WNDCLASSEX); | |
204 wcex.style = CS_HREDRAW | CS_VREDRAW; | |
205 wcex.lpfnWndProc = WndProc; | |
206 wcex.cbClsExtra = 0; | |
207 wcex.cbWndExtra = 0; | |
208 wcex.hInstance = hInstance; | |
209 wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); | |
210 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); | |
211 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); | |
212 wcex.lpszMenuName = NULL; | |
213 wcex.lpszClassName = szWindowClass; | |
214 wcex.hIconSm = LoadIcon(wcex.hInstance, | |
215 MAKEINTRESOURCE(IDI_APPLICATION)); | |
216 | |
217 if (!RegisterClassEx(&wcex)) { | |
218 MessageBox(NULL, | |
219 _T("Call to RegisterClassEx failed!"), | |
220 _T("hello_nacl_plus"), | |
221 NULL); | |
222 | |
223 return 1; | |
224 } | |
225 | |
226 hInst = hInstance; | |
227 | |
228 HWND hWnd = CreateWindow( | |
229 szWindowClass, | |
230 szTitle, | |
231 WS_OVERLAPPEDWINDOW, | |
232 CW_USEDEFAULT, CW_USEDEFAULT, | |
233 500, 100, | |
234 NULL, | |
235 NULL, | |
236 hInstance, | |
237 NULL); | |
238 | |
239 if (!hWnd) { | |
240 MessageBox(NULL, | |
241 _T("Call to CreateWindow failed!"), | |
242 _T("hello_nacl_plus"), | |
243 NULL); | |
244 | |
245 return 1; | |
246 } | |
247 | |
248 ShowWindow(hWnd, | |
249 nCmdShow); | |
250 UpdateWindow(hWnd); | |
251 | |
252 // Main message loop: | |
253 MSG msg; | |
254 while (GetMessage(&msg, NULL, 0, 0)) { | |
255 TranslateMessage(&msg); | |
256 DispatchMessage(&msg); | |
257 } | |
258 | |
259 return (int) msg.wParam; | |
260 } | |
261 | |
262 // WndProc | |
263 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) | |
264 { | |
265 PAINTSTRUCT ps; | |
266 HDC hdc; | |
267 TCHAR greeting[] = _T("Hello, World!"); | |
268 | |
269 switch (message) | |
270 { | |
271 case WM_PAINT: | |
272 hdc = BeginPaint(hWnd, &ps); | |
273 | |
274 // Here your application is laid out. | |
275 // For this introduction, we just print out "Hello, World!" | |
276 // in the top left corner. | |
277 TextOut(hdc, | |
278 5, 5, | |
279 greeting, _tcslen(greeting)); | |
280 // End application-specific layout section. | |
281 | |
282 EndPaint(hWnd, &ps); | |
283 break; | |
284 case WM_DESTROY: | |
285 PostQuitMessage(0); | |
286 break; | |
287 default: | |
288 return DefWindowProc(hWnd, message, wParam, lParam); | |
289 break; | |
290 } | |
291 | |
292 return 0; | |
293 } | |
294 #endif | |
295 | |
296 #ifdef STEP3 | |
297 // Replace WinMain with initInstanceInPCWindow so the NativeClient Module can | |
298 // launch the original application. | |
299 // Note the inclusion of a message-handling loop. STEP4 will replace the loop | |
300 // with a callback. | |
301 | |
302 void shutDown(void); | |
303 HINSTANCE g_hInstance = NULL; | |
304 HWND g_hWnd = NULL; | |
305 | |
306 int initInstanceInPCWindow() | |
307 { | |
308 WNDCLASSEX winClass; | |
309 MSG uMsg; | |
310 | |
311 memset(&uMsg,0,sizeof(uMsg)); | |
312 | |
313 winClass.lpszClassName = _T("MY_WINDOWS_CLASS"); | |
314 winClass.cbSize = sizeof(WNDCLASSEX); | |
315 winClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; | |
316 winClass.lpfnWndProc = WndProc; | |
317 winClass.hInstance = g_hInstance; | |
318 winClass.hIcon = NULL; | |
319 winClass.hIconSm = NULL; | |
320 winClass.hCursor = LoadCursor(NULL, IDC_ARROW); | |
321 winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); | |
322 winClass.lpszMenuName = NULL; | |
323 winClass.cbClsExtra = 0; | |
324 winClass.cbWndExtra = 0; | |
325 | |
326 if (!RegisterClassEx(&winClass)) | |
327 return E_FAIL; | |
328 | |
329 g_hWnd = CreateWindowEx(NULL,_T("MY_WINDOWS_CLASS"), | |
330 _T("hello_nacl_plus"), | |
331 WS_OVERLAPPEDWINDOW, | |
332 0,0, 640, 480, NULL, NULL, g_hInstance, NULL); | |
333 | |
334 if (g_hWnd == NULL) | |
335 return E_FAIL; | |
336 | |
337 ShowWindow(g_hWnd, 1); | |
338 | |
339 UpdateWindow(g_hWnd); | |
340 | |
341 #ifdef STEP4 | |
342 // Skip the message loop, schedule a callback instead to periodically check | |
343 // for messages. Here we schedule at 100ms intervals. | |
344 myInstance->SendCallback(0); | |
345 return 0; | |
346 #else | |
347 // Main message loop, Windows style. | |
348 while(uMsg.message != WM_QUIT) { | |
349 if (PeekMessage(&uMsg, NULL, 0, 0, PM_REMOVE)) { | |
350 TranslateMessage(&uMsg); | |
351 DispatchMessage(&uMsg); | |
352 } | |
353 } | |
354 return uMsg.wParam; | |
355 #endif | |
356 | |
357 } | |
358 #endif | |
359 | |
360 #ifdef STEP5 | |
361 // Pass the text to the browser page, there is no separate app window anymore. | |
362 // The text is added as a new element to the page, it does not appear in the | |
363 // module's embed view. | |
364 void initInstanceInBrowserWindow() { | |
365 myInstance->PostMessage(pp::Var("Hello, Native Client!")); | |
366 } | |
367 #endif | |
OLD | NEW |