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