Chromium Code Reviews| 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 HelloNaCl in its own window. | |
| 34 // Since WndProc spins in its message loop, the call to Instance_DidCreate | |
| 35 // never returns. | |
| 36 // Close the HelloNaCl 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 <project | |
|
binji
2012/10/15 22:15:46
nit: line break here seems a little odd
Sam Clegg
2012/10/15 22:54:52
Done.
| |
| 62 // directory>/newlib/HelloNaCl/HelloNaCl.nexe exists | |
| 63 // - Copy the folder <project directory>/HelloNaCl 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/HelloNaCl | |
| 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() { | |
|
binji
2012/10/15 22:15:46
capitalize
Sam Clegg
2012/10/15 22:54:52
Done.
| |
| 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, CStrToVar("Hello, Native | |
|
binji
2012/10/15 22:15:46
don't line-break in string
Sam Clegg
2012/10/15 22:54:52
Done.
| |
| 143 Client!")); } | |
| 144 | |
| 145 /** | |
| 146 * Called when the NaCl module is instantiated on the web page. | |
| 147 */ | |
| 148 static PP_Bool Instance_DidCreate(PP_Instance instance, | |
| 149 uint32_t argc, | |
| 150 const char* argn[], | |
| 151 const char* argv[]) { | |
| 152 myInstance = instance; | |
| 153 ppb_messaging_interface->PostMessage(instance, | |
| 154 CStrToVar("Start Instance_DidCreate")); | |
| 155 #ifdef STEP5 | |
| 156 // Will be included in STEP5 and STEP6 | |
| 157 // Uses messaging to relay text to the module's view on the web page | |
| 158 initInstanceInBrowserWindow(); | |
| 159 #else | |
| 160 #ifdef STEP3 | |
| 161 // Will be included in STEP3 and STEP4 only | |
| 162 // Uses WndProc to place text in a window separate from the browser. | |
| 163 initInstanceInPCWindow(); | |
|
binji
2012/10/15 22:15:46
capitalize
Sam Clegg
2012/10/15 22:54:52
Done.
| |
| 164 #endif | |
| 165 #endif | |
| 166 | |
| 167 ppb_messaging_interface->PostMessage(instance, | |
| 168 CStrToVar("End Instance_DidCreate")); | |
| 169 return PP_TRUE; | |
| 170 } | |
| 171 | |
| 172 /** | |
| 173 * Called when the NaCl module is destroyed. | |
| 174 */ | |
| 175 static void Instance_DidDestroy(PP_Instance instance) { | |
| 176 } | |
| 177 | |
| 178 /** | |
| 179 * Called when the position, the size, or the clip rect of the element in the | |
| 180 * browser that corresponds to this NaCl module has changed. | |
| 181 */ | |
| 182 static void Instance_DidChangeView(PP_Instance instance, | |
| 183 PP_Resource view_resource) { | |
| 184 } | |
| 185 | |
| 186 /** | |
| 187 * Notification that the given NaCl module has gained or lost focus. | |
| 188 */ | |
| 189 static void Instance_DidChangeFocus(PP_Instance instance, | |
| 190 PP_Bool has_focus) { | |
| 191 } | |
| 192 | |
| 193 /** | |
| 194 * Handler that gets called after a full-frame module is instantiated based on | |
| 195 * registered MIME types. This function is not called on NaCl modules. This | |
| 196 * function is essentially a place-holder for the required function pointer in | |
| 197 * the PPP_Instance structure. | |
| 198 */ | |
| 199 static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance, | |
| 200 PP_Resource url_loader) { | |
| 201 /* NaCl modules do not need to handle the document load function. */ | |
| 202 return PP_FALSE; | |
| 203 } | |
| 204 | |
|
binji
2012/10/15 22:15:46
remove extra newlines
Sam Clegg
2012/10/15 22:54:52
Done.
| |
| 205 | |
| 206 | |
| 207 /** | |
| 208 * Entry points for the module. | |
| 209 * Initialize needed interfaces: PPB_Core, PPB_Messaging and PPB_Var. | |
| 210 */ | |
| 211 PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id, | |
| 212 PPB_GetInterface get_browser) { | |
| 213 ppb_messaging_interface = (PPB_Messaging*) | |
| 214 get_browser(PPB_MESSAGING_INTERFACE); | |
| 215 ppb_var_interface = (PPB_Var*)get_browser(PPB_VAR_INTERFACE); | |
| 216 ppb_core_interface = (PPB_Core*)get_browser(PPB_CORE_INTERFACE); | |
| 217 return PP_OK; | |
| 218 } | |
| 219 | |
| 220 | |
| 221 /** | |
| 222 * Returns an interface pointer for the interface of the given name, or NULL | |
| 223 * if the interface is not supported. | |
| 224 */ | |
| 225 PP_EXPORT const void* PPP_GetInterface(const char* interface_name) { | |
| 226 if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) { | |
| 227 static PPP_Instance instance_interface = { | |
| 228 &Instance_DidCreate, | |
| 229 &Instance_DidDestroy, | |
| 230 &Instance_DidChangeView, | |
| 231 &Instance_DidChangeFocus, | |
| 232 &Instance_HandleDocumentLoad, | |
| 233 }; | |
| 234 return &instance_interface; | |
| 235 } | |
| 236 return NULL; | |
| 237 } | |
| 238 | |
| 239 | |
| 240 /** | |
| 241 * Called before the plugin module is unloaded. | |
| 242 */ | |
| 243 PP_EXPORT void PPP_ShutdownModule() { | |
| 244 } | |
| 245 #endif | |
| 246 | |
| 247 | |
| 248 | |
| 249 // **** Application Code **** | |
| 250 | |
| 251 #ifdef STEP1 | |
| 252 // Desktop Windows Hello World app. Native Client agnostic. | |
| 253 | |
| 254 static TCHAR szWindowClass[] = _T("win32app"); | |
| 255 static TCHAR szTitle[] = _T("HelloNaCl"); | |
| 256 HINSTANCE hInst; | |
| 257 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); | |
| 258 | |
| 259 // WinMain | |
| 260 int WINAPI WinMain(HINSTANCE hInstance, | |
| 261 HINSTANCE hPrevInstance, | |
| 262 LPSTR lpCmdLine, | |
| 263 int nCmdShow) { | |
| 264 WNDCLASSEX wcex; | |
| 265 HWND hWnd; | |
| 266 MSG msg; | |
| 267 | |
| 268 wcex.cbSize = sizeof(WNDCLASSEX); | |
| 269 wcex.style = CS_HREDRAW | CS_VREDRAW; | |
| 270 wcex.lpfnWndProc = WndProc; | |
| 271 wcex.cbClsExtra = 0; | |
| 272 wcex.cbWndExtra = 0; | |
| 273 wcex.hInstance = hInstance; | |
| 274 wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); | |
| 275 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); | |
| 276 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); | |
| 277 wcex.lpszMenuName = NULL; | |
| 278 wcex.lpszClassName = szWindowClass; | |
| 279 wcex.hIconSm = LoadIcon(wcex.hInstance, | |
| 280 MAKEINTRESOURCE(IDI_APPLICATION)); | |
| 281 | |
| 282 if (!RegisterClassEx(&wcex)) { | |
| 283 MessageBox(NULL, | |
|
binji
2012/10/15 22:15:46
NULL on next line, indent by 4
Sam Clegg
2012/10/15 22:54:52
Done.
| |
| 284 _T("Call to RegisterClassEx failed!"), | |
| 285 _T("HelloNaCl"), | |
| 286 0); | |
| 287 | |
| 288 return 1; | |
| 289 } | |
| 290 | |
| 291 hInst = hInstance; | |
| 292 | |
| 293 hWnd = CreateWindow( | |
| 294 szWindowClass, | |
| 295 szTitle, | |
| 296 WS_OVERLAPPEDWINDOW, | |
| 297 CW_USEDEFAULT, CW_USEDEFAULT, | |
| 298 500, 100, | |
| 299 NULL, | |
| 300 NULL, | |
| 301 hInstance, | |
| 302 NULL | |
|
binji
2012/10/15 22:15:46
close paren on this line
Sam Clegg
2012/10/15 22:54:52
Done.
| |
| 303 ); | |
| 304 | |
| 305 if (!hWnd) { | |
| 306 MessageBox(NULL, | |
|
binji
2012/10/15 22:15:46
NULL on next line, indent by 4
Sam Clegg
2012/10/15 22:54:52
Done.
| |
| 307 _T("Call to CreateWindow failed!"), | |
| 308 _T("HelloNaCl"), | |
| 309 0); | |
| 310 | |
| 311 return 1; | |
| 312 } | |
| 313 | |
| 314 ShowWindow(hWnd, nCmdShow); | |
| 315 UpdateWindow(hWnd); | |
| 316 | |
| 317 // Main message loop: | |
| 318 | |
| 319 while (GetMessage(&msg, NULL, 0, 0)) { | |
| 320 TranslateMessage(&msg); | |
| 321 DispatchMessage(&msg); | |
| 322 } | |
| 323 | |
| 324 return (int) msg.wParam; | |
| 325 } | |
| 326 | |
| 327 // WndProc | |
| 328 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) | |
|
binji
2012/10/15 22:15:46
brace on this line
Sam Clegg
2012/10/15 22:54:52
Done.
| |
| 329 { | |
| 330 PAINTSTRUCT ps; | |
| 331 HDC hdc; | |
| 332 TCHAR greeting[] = _T("Hello, World!"); | |
| 333 | |
| 334 switch (message) { | |
| 335 case WM_PAINT: | |
| 336 hdc = BeginPaint(hWnd, &ps); | |
| 337 TextOut(hdc, 5, 5, greeting, _tcslen(greeting)); | |
| 338 EndPaint(hWnd, &ps); | |
| 339 break; | |
| 340 case WM_DESTROY: | |
| 341 PostQuitMessage(0); | |
| 342 break; | |
| 343 default: | |
| 344 return DefWindowProc(hWnd, message, wParam, lParam); | |
| 345 break; | |
| 346 } | |
| 347 | |
| 348 return 0; | |
| 349 } | |
| 350 #endif | |
| 351 | |
| 352 #ifdef STEP3 | |
| 353 // Replace WinMain with initInstanceInPCWindow so the Native Client Module can | |
| 354 // launch the original application. Note the inclusion of a message-handling | |
| 355 // loop. STEP4 will replace the loop with a callback. | |
| 356 HINSTANCE g_hInstance = NULL; HWND g_hWnd = NULL; int initInstanceInPCWindow() | |
|
binji
2012/10/15 22:15:46
one line per declaration
Sam Clegg
2012/10/15 22:54:52
Done.
| |
| 357 { WNDCLASSEX winClass; MSG uMsg; | |
|
binji
2012/10/15 22:15:46
brace on previous line, declarations have their ow
Sam Clegg
2012/10/15 22:54:52
Done.
| |
| 358 | |
| 359 memset(&uMsg,0,sizeof(uMsg)); | |
| 360 | |
| 361 winClass.lpszClassName = _T("MY_WINDOWS_CLASS"); | |
| 362 winClass.cbSize = sizeof(WNDCLASSEX); | |
| 363 winClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; | |
| 364 winClass.lpfnWndProc = WndProc; | |
| 365 winClass.hInstance = g_hInstance; | |
| 366 winClass.hIcon = NULL; | |
| 367 winClass.hIconSm = NULL; | |
| 368 winClass.hCursor = LoadCursor(NULL, IDC_ARROW); | |
| 369 winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); | |
| 370 winClass.lpszMenuName = NULL; | |
| 371 winClass.cbClsExtra = 0; | |
| 372 winClass.cbWndExtra = 0; | |
| 373 | |
| 374 if (!RegisterClassEx(&winClass)) | |
| 375 return E_FAIL; | |
| 376 | |
| 377 g_hWnd = CreateWindowEx(NULL, _T("MY_WINDOWS_CLASS"), | |
|
binji
2012/10/15 22:15:46
params start on next line, one per line (or groupe
Sam Clegg
2012/10/15 22:54:52
Done.
| |
| 378 _T("HelloNaCl"), | |
| 379 WS_OVERLAPPEDWINDOW, | |
| 380 0, 0, 640,480, NULL, NULL, g_hInstance, NULL); | |
| 381 | |
| 382 if (g_hWnd == NULL) | |
| 383 return E_FAIL; | |
| 384 | |
| 385 ShowWindow(g_hWnd, 1); | |
| 386 | |
| 387 UpdateWindow(g_hWnd); | |
| 388 | |
| 389 #ifdef STEP4 | |
| 390 // Skip the message loop, schedule a callback instead to periodically check | |
| 391 // for messages. Here we schedule at 100ms intervals. | |
| 392 ppb_core_interface->CallOnMainThread(100, HelloWorldCallback, 0); | |
| 393 return 0; | |
| 394 #else | |
| 395 // Main message loop, Windows style. | |
| 396 while(uMsg.message != WM_QUIT) { | |
| 397 if (PeekMessage(&uMsg, NULL, 0, 0, PM_REMOVE)) { | |
| 398 TranslateMessage( &uMsg ); | |
| 399 DispatchMessage( &uMsg ); | |
| 400 } | |
| 401 } | |
| 402 return uMsg.wParam; | |
| 403 #endif | |
| 404 | |
| 405 } | |
| 406 #endif | |
| OLD | NEW |