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 // What Changed: The platform launches Chrome, which will then load a Native | |
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 in its own window. | |
34 // Since WndProc spins in its message loop, the call to Instance_DidCreate | |
35 // never returns. | |
36 // Close the hello_nacl window and the module initialization will 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. | |
45 // The InitInstanceInBrowserWindow uses postMessage to place text (now "Hello, | |
46 // Native Client") in the web page 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>/NaCl64/newlib/Debug/hello_nacl_64.nexe exists | |
63 // - Copy the folder <project directory> into your NaCl SDK's example | |
64 // 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 | |
69 | |
70 | |
71 #ifdef STEP6 | |
72 // remove Windows-dependent code. | |
73 #undef STEP1 | |
74 #undef STEP3 | |
75 #undef STEP4 | |
76 #define NULL 0 | |
77 #else | |
78 // includes for Windows APIs. | |
79 #include <windows.h> | |
80 #include <stdlib.h> | |
81 #include <tchar.h> | |
82 #endif | |
83 | |
84 | |
85 #ifdef STEP2 | |
86 // includes for PPAPI | |
87 #include "ppapi/c/pp_errors.h" | |
88 #include "ppapi/c/pp_module.h" | |
89 #include "ppapi/c/pp_var.h" | |
90 #include "ppapi/c/ppb.h" | |
91 #include "ppapi/c/ppb_instance.h" | |
92 #include "ppapi/c/ppb_messaging.h" | |
93 #include "ppapi/c/ppb_var.h" | |
94 #include "ppapi/c/ppb_core.h" | |
95 #include "ppapi/c/ppp.h" | |
96 #include "ppapi/c/ppp_instance.h" | |
97 #include "ppapi/c/ppp_messaging.h" | |
98 #include <string.h> | |
99 | |
100 // Native Client APIs | |
101 static PPB_Messaging* ppb_messaging_interface = NULL; | |
102 static PPB_Var* ppb_var_interface = NULL; | |
103 static PPB_Core* ppb_core_interface = NULL; | |
104 PP_Instance myInstance; | |
105 | |
106 int InitInstanceInPCWindow(); | |
107 void InitInstanceInBrowserWindow(); | |
108 | |
109 #endif | |
110 | |
111 | |
112 #ifdef STEP4 | |
113 // Implements message handling in a callback function. | |
114 void HelloWorldCallback(void* user_data, int32_t result) { | |
115 MSG uMsg; | |
116 if (PeekMessage(&uMsg, NULL, 0, 0, PM_REMOVE)) { | |
117 TranslateMessage(&uMsg); | |
118 DispatchMessage(&uMsg); | |
119 } | |
120 ppb_core_interface->CallOnMainThread(100, HelloWorldCallback, 0); | |
121 } | |
122 | |
123 struct PP_CompletionCallback HelloWorldCallback = { HelloWorldCallback, NULL }; | |
124 #endif | |
125 | |
126 #ifdef STEP2 | |
127 // The basic framework needed for all Native Client Modules. Handles creation | |
128 // of the module instance and initial handshake with the browser. | |
129 /** | |
130 * Creates new string PP_Var from C string. Useful utility for | |
131 * message-handling. | |
132 */ | |
133 static struct PP_Var CStrToVar(const char* str) { if (ppb_var_interface != | |
134 NULL) { return ppb_var_interface->VarFromUtf8(str, strlen(str)); } return | |
135 PP_MakeUndefined(); } | |
136 | |
137 | |
138 void InitInstanceInBrowserWindow() { | |
139 // Pass the text to the browser page, there is no separate app window | |
140 // anymore. The text is added as a new element to the page, it does not | |
141 // appear in the module's embed view. | |
142 ppb_messaging_interface->PostMessage(myInstance, | |
143 CStrToVar("Hello, Native Client!")); | |
144 } | |
145 | |
146 /** | |
147 * Called when the NaCl module is instantiated on the web page. | |
148 */ | |
149 static PP_Bool Instance_DidCreate(PP_Instance instance, | |
150 uint32_t argc, | |
151 const char* argn[], | |
152 const char* argv[]) { | |
153 myInstance = instance; | |
154 ppb_messaging_interface->PostMessage(instance, | |
155 CStrToVar("Start Instance_DidCreate")); | |
156 #ifdef STEP5 | |
157 // Will be included in STEP5 and STEP6 | |
158 // Uses messaging to relay text to the module's view on the web page | |
159 InitInstanceInBrowserWindow(); | |
160 #else | |
161 #ifdef STEP3 | |
162 // Will be included in STEP3 and STEP4 only | |
163 // Uses WndProc to place text in a window separate from the browser. | |
164 InitInstanceInPCWindow(); | |
165 #endif | |
166 #endif | |
167 | |
168 ppb_messaging_interface->PostMessage(instance, | |
169 CStrToVar("End Instance_DidCreate")); | |
170 return PP_TRUE; | |
171 } | |
172 | |
173 /** | |
174 * Called when the NaCl module is destroyed. | |
175 */ | |
176 static void Instance_DidDestroy(PP_Instance instance) { | |
177 } | |
178 | |
179 /** | |
180 * Called when the position, the size, or the clip rect of the element in the | |
181 * browser that corresponds to this NaCl module has changed. | |
182 */ | |
183 static void Instance_DidChangeView(PP_Instance instance, | |
184 PP_Resource view_resource) { | |
185 } | |
186 | |
187 /** | |
188 * Notification that the given NaCl module has gained or lost focus. | |
189 */ | |
190 static void Instance_DidChangeFocus(PP_Instance instance, | |
191 PP_Bool has_focus) { | |
192 } | |
193 | |
194 /** | |
195 * Handler that gets called after a full-frame module is instantiated based on | |
196 * registered MIME types. This function is not called on NaCl modules. This | |
197 * function is essentially a place-holder for the required function pointer in | |
198 * the PPP_Instance structure. | |
199 */ | |
200 static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance, | |
201 PP_Resource url_loader) { | |
202 /* NaCl modules do not need to handle the document load function. */ | |
203 return PP_FALSE; | |
204 } | |
205 | |
206 /** | |
207 * Entry points for the module. | |
208 * Initialize needed interfaces: PPB_Core, PPB_Messaging and PPB_Var. | |
209 */ | |
210 PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id, | |
211 PPB_GetInterface get_browser) { | |
212 ppb_messaging_interface = (PPB_Messaging*) | |
213 get_browser(PPB_MESSAGING_INTERFACE); | |
214 ppb_var_interface = (PPB_Var*)get_browser(PPB_VAR_INTERFACE); | |
215 ppb_core_interface = (PPB_Core*)get_browser(PPB_CORE_INTERFACE); | |
216 return PP_OK; | |
217 } | |
218 | |
219 /** | |
220 * Returns an interface pointer for the interface of the given name, or NULL | |
221 * if the interface is not supported. | |
222 */ | |
223 PP_EXPORT const void* PPP_GetInterface(const char* interface_name) { | |
224 if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) { | |
225 static PPP_Instance instance_interface = { | |
226 &Instance_DidCreate, | |
227 &Instance_DidDestroy, | |
228 &Instance_DidChangeView, | |
229 &Instance_DidChangeFocus, | |
230 &Instance_HandleDocumentLoad, | |
231 }; | |
232 return &instance_interface; | |
233 } | |
234 return NULL; | |
235 } | |
236 | |
237 /** | |
238 * Called before the plugin module is unloaded. | |
239 */ | |
240 PP_EXPORT void PPP_ShutdownModule() { | |
241 } | |
242 #endif | |
243 | |
244 // **** Application Code **** | |
245 | |
246 #ifdef STEP1 | |
247 // Desktop Windows Hello World app. Native Client agnostic. | |
248 | |
249 static TCHAR szWindowClass[] = _T("win32app"); | |
250 static TCHAR szTitle[] = _T("hello_nacl"); | |
251 HINSTANCE hInst; | |
252 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); | |
253 | |
254 // WinMain | |
255 int WINAPI WinMain(HINSTANCE hInstance, | |
256 HINSTANCE hPrevInstance, | |
257 LPSTR lpCmdLine, | |
258 int nCmdShow) { | |
259 WNDCLASSEX wcex; | |
260 HWND hWnd; | |
261 MSG msg; | |
262 | |
263 wcex.cbSize = sizeof(WNDCLASSEX); | |
264 wcex.style = CS_HREDRAW | CS_VREDRAW; | |
265 wcex.lpfnWndProc = WndProc; | |
266 wcex.cbClsExtra = 0; | |
267 wcex.cbWndExtra = 0; | |
268 wcex.hInstance = hInstance; | |
269 wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); | |
270 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); | |
271 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); | |
272 wcex.lpszMenuName = NULL; | |
273 wcex.lpszClassName = szWindowClass; | |
274 wcex.hIconSm = LoadIcon(wcex.hInstance, | |
275 MAKEINTRESOURCE(IDI_APPLICATION)); | |
276 | |
277 if (!RegisterClassEx(&wcex)) { | |
278 MessageBox(NULL, | |
279 _T("Call to RegisterClassEx failed!"), | |
280 _T("hello_nacl"), | |
281 0); | |
282 | |
283 return 1; | |
284 } | |
285 | |
286 hInst = hInstance; | |
287 | |
288 hWnd = CreateWindow( | |
289 szWindowClass, | |
290 szTitle, | |
291 WS_OVERLAPPEDWINDOW, | |
292 CW_USEDEFAULT, CW_USEDEFAULT, | |
293 500, 100, | |
294 NULL, | |
295 NULL, | |
296 hInstance, | |
297 NULL); | |
298 | |
299 if (!hWnd) { | |
300 MessageBox(NULL, | |
301 _T("Call to CreateWindow failed!"), | |
302 _T("hello_nacl"), | |
303 0); | |
304 | |
305 return 1; | |
306 } | |
307 | |
308 ShowWindow(hWnd, nCmdShow); | |
309 UpdateWindow(hWnd); | |
310 | |
311 // Main message loop: | |
312 | |
313 while (GetMessage(&msg, NULL, 0, 0)) { | |
314 TranslateMessage(&msg); | |
315 DispatchMessage(&msg); | |
316 } | |
317 | |
318 return (int) msg.wParam; | |
319 } | |
320 | |
321 // WndProc | |
322 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, | |
323 WPARAM wParam, LPARAM lParam) { | |
324 PAINTSTRUCT ps; | |
325 HDC hdc; | |
326 TCHAR greeting[] = _T("Hello, World!"); | |
327 | |
328 switch (message) { | |
329 case WM_PAINT: | |
330 hdc = BeginPaint(hWnd, &ps); | |
331 TextOut(hdc, 5, 5, greeting, _tcslen(greeting)); | |
332 EndPaint(hWnd, &ps); | |
333 break; | |
334 case WM_DESTROY: | |
335 PostQuitMessage(0); | |
336 break; | |
337 default: | |
338 return DefWindowProc(hWnd, message, wParam, lParam); | |
339 break; | |
340 } | |
341 | |
342 return 0; | |
343 } | |
344 #endif | |
345 | |
346 #ifdef STEP3 | |
347 // Replace WinMain with InitInstanceInPCWindow so the Native Client Module can | |
348 // launch the original application. Note the inclusion of a message-handling | |
349 // loop. STEP4 will replace the loop with a callback. | |
350 HINSTANCE g_hInstance = NULL; | |
351 HWND g_hWnd = NULL; | |
352 | |
353 int InitInstanceInPCWindow() | |
binji
2012/10/15 23:03:07
brace on this line
| |
354 { | |
355 WNDCLASSEX winClass; MSG uMsg; | |
356 | |
357 memset(&uMsg,0,sizeof(uMsg)); | |
358 | |
359 winClass.lpszClassName = _T("MY_WINDOWS_CLASS"); | |
360 winClass.cbSize = sizeof(WNDCLASSEX); | |
361 winClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; | |
362 winClass.lpfnWndProc = WndProc; | |
363 winClass.hInstance = g_hInstance; | |
364 winClass.hIcon = NULL; | |
365 winClass.hIconSm = NULL; | |
366 winClass.hCursor = LoadCursor(NULL, IDC_ARROW); | |
367 winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); | |
368 winClass.lpszMenuName = NULL; | |
369 winClass.cbClsExtra = 0; | |
370 winClass.cbWndExtra = 0; | |
371 | |
372 if (!RegisterClassEx(&winClass)) | |
373 return E_FAIL; | |
374 | |
375 g_hWnd = CreateWindowEx( | |
376 NULL, _T("MY_WINDOWS_CLASS"), | |
377 _T("hello_nacl"), WS_OVERLAPPEDWINDOW, | |
378 0, 0, 640, 480, NULL, NULL, g_hInstance, NULL); | |
379 | |
380 if (g_hWnd == NULL) | |
381 return E_FAIL; | |
382 | |
383 ShowWindow(g_hWnd, 1); | |
384 | |
385 UpdateWindow(g_hWnd); | |
386 | |
387 #ifdef STEP4 | |
388 // Skip the message loop, schedule a callback instead to periodically check | |
389 // for messages. Here we schedule at 100ms intervals. | |
390 ppb_core_interface->CallOnMainThread(100, HelloWorldCallback, 0); | |
391 return 0; | |
392 #else | |
393 // Main message loop, Windows style. | |
394 while(uMsg.message != WM_QUIT) { | |
395 if (PeekMessage(&uMsg, NULL, 0, 0, PM_REMOVE)) { | |
396 TranslateMessage( &uMsg ); | |
397 DispatchMessage( &uMsg ); | |
398 } | |
399 } | |
400 return uMsg.wParam; | |
401 #endif | |
402 | |
403 } | |
404 #endif | |
OLD | NEW |