{"id":35813,"date":"2005-04-22T09:00:08","date_gmt":"2005-04-22T09:00:08","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2005\/04\/22\/the-new-scratch-program\/"},"modified":"2005-04-22T09:00:08","modified_gmt":"2005-04-22T09:00:08","slug":"the-new-scratch-program","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050422-08\/?p=35813","title":{"rendered":"The new scratch program"},"content":{"rendered":"<p>\nI think it&#8217;s time to update the scratch program we&#8217;ve been\nusing for the past year.\nI hear there&#8217;s this new language called C++ that&#8217;s going to become\nreally popular any day now,\nso let&#8217;s hop on the bandwagon!\n<\/p>\n<pre>\n#define STRICT\n#define UNICODE\n#define _UNICODE\n#include &lt;windows.h&gt;\n#include &lt;windowsx.h&gt;\n#include &lt;ole2.h&gt;\n#include &lt;commctrl.h&gt;\n#include &lt;shlwapi.h&gt;\n#include &lt;shlobj.h&gt;\n#include &lt;shellapi.h&gt;\nHINSTANCE g_hinst;\nclass Window\n{\npublic:\n HWND GetHWND() { return m_hwnd; }\nprotected:\n virtual LRESULT HandleMessage(\n                         UINT uMsg, WPARAM wParam, LPARAM lParam);\n virtual void PaintContent(PAINTSTRUCT *pps) { }\n virtual LPCTSTR ClassName() = 0;\n virtual BOOL WinRegisterClass(WNDCLASS *pwc)\n     { return RegisterClass(pwc); }\n virtual ~Window() { }\n HWND WinCreateWindow(DWORD dwExStyle, LPCTSTR pszName,\n       DWORD dwStyle, int x, int y, int cx, int cy,\n       HWND hwndParent, HMENU hmenu)\n {\n  Register();\n  return CreateWindowEx(dwExStyle, ClassName(), pszName, dwStyle,\n                  x, y, cx, cy, hwndParent, hmenu, g_hinst, this);\n }\nprivate:\n void Register();\n void OnPaint();\n void OnPrintClient(HDC hdc);\n static LRESULT CALLBACK s_WndProc(HWND hwnd,\n     UINT uMsg, WPARAM wParam, LPARAM lParam);\nprotected:\n HWND m_hwnd;\n};\nvoid Window::Register()\n{\n    WNDCLASS wc;\n    wc.style         = 0;\n    wc.lpfnWndProc   = Window::s_WndProc;\n    wc.cbClsExtra    = 0;\n    wc.cbWndExtra    = 0;\n    wc.hInstance     = g_hinst;\n    wc.hIcon         = NULL;\n    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);\n    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);\n    wc.lpszMenuName  = NULL;\n    wc.lpszClassName = ClassName();\n    WinRegisterClass(&amp;wc);\n}\nLRESULT CALLBACK Window::s_WndProc(\n               HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n{\n Window *self;\n if (uMsg == WM_NCCREATE) {\n  LPCREATESTRUCT lpcs = reinterpret_cast&lt;LPCREATESTRUCT&gt;(lParam);\n  self = reinterpret_cast&lt;Window *&gt;(lpcs-&gt;lpCreateParams);\n  self-&gt;m_hwnd = hwnd;\n  SetWindowLongPtr(hwnd, GWLP_USERDATA,\n            reinterpret_cast&lt;LPARAM&gt;(self));\n } else {\n  self = reinterpret_cast&lt;Window *&gt;\n            (GetWindowLongPtr(hwnd, GWLP_USERDATA));\n }\n if (self) {\n  return self-&gt;HandleMessage(uMsg, wParam, lParam);\n } else {\n  return DefWindowProc(hwnd, uMsg, wParam, lParam);\n }\n}\nLRESULT Window::HandleMessage(\n                          UINT uMsg, WPARAM wParam, LPARAM lParam)\n{\n LRESULT lres;\n switch (uMsg) {\n case WM_NCDESTROY:\n  lres = DefWindowProc(m_hwnd, uMsg, wParam, lParam);\n  SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0);\n  delete this;\n  return lres;\n case WM_PAINT:\n  OnPaint();\n  return 0;\n case WM_PRINTCLIENT:\n  OnPrintClient(reinterpret_cast&lt;HDC&gt;(wParam));\n  return 0;\n }\n return DefWindowProc(m_hwnd, uMsg, wParam, lParam);\n}\nvoid Window::OnPaint()\n{\n PAINTSTRUCT ps;\n BeginPaint(m_hwnd, &amp;ps);\n PaintContent(&amp;ps);\n EndPaint(m_hwnd, &amp;ps);\n}\nvoid Window::OnPrintClient(HDC hdc)\n{\n PAINTSTRUCT ps;\n ps.hdc = hdc;\n GetClientRect(m_hwnd, &amp;ps.rcPaint);\n PaintContent(&amp;ps);\n}\nclass RootWindow : public Window\n{\npublic:\n virtual LPCTSTR ClassName() { return TEXT(\"Scratch\"); }\n static RootWindow *Create();\nprotected:\n LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);\n LRESULT OnCreate();\nprivate:\n HWND m_hwndChild;\n};\nLRESULT RootWindow::OnCreate()\n{\n return 0;\n}\nLRESULT RootWindow::HandleMessage(\n                          UINT uMsg, WPARAM wParam, LPARAM lParam)\n{\n switch (uMsg) {\n  case WM_CREATE:\n   return OnCreate();\n  case WM_NCDESTROY:\n   \/\/ Death of the root window ends the thread\n   PostQuitMessage(0);\n   break;\n  case WM_SIZE:\n   if (m_hwndChild) {\n    SetWindowPos(m_hwndChild, NULL, 0, 0,\n                 GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),\n                 SWP_NOZORDER | SWP_NOACTIVATE);\n   }\n   return 0;\n  case WM_SETFOCUS:\n   if (m_hwndChild) {\n    SetFocus(m_hwndChild);\n   }\n   return 0;\n }\n return __super::HandleMessage(uMsg, wParam, lParam);\n}\nRootWindow *RootWindow::Create()\n{\n RootWindow *self = new RootWindow();\n if (self &amp;&amp; self-&gt;WinCreateWindow(0,\n       TEXT(\"Scratch\"), WS_OVERLAPPEDWINDOW,\n       CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,\n       NULL, NULL)) {\n      return self;\n  }\n delete self;\n return NULL;\n}\nint PASCAL\nWinMain(HINSTANCE hinst, HINSTANCE, LPSTR, int nShowCmd)\n{\n g_hinst = hinst;\n if (SUCCEEDED(CoInitialize(NULL))) {\n  InitCommonControls();\n  RootWindow *prw = RootWindow::Create();\n  if (prw) {\n   ShowWindow(prw-&gt;GetHWND(), nShowCmd);\n   MSG msg;\n   while (GetMessage(&amp;msg, NULL, 0, 0)) {\n    TranslateMessage(&amp;msg);\n    DispatchMessage(&amp;msg);\n   }\n  }\n  CoUninitialize();\n }\n return 0;\n}\n<\/pre>\n<p>\nThe basic idea of this program is the same as our old\nscratch program, but now it has that fresh lemony C++ scent.\nInstead of keeping our state in globals, we declare a C++ class\nand hook it up to the window.\nFor simplicity,\nthe object&#8217;s lifetime is tied to the window itself.\n<\/p>\n<p>\nFirst, there is a bare-bones <code>Window<\/code> class which we\nwill use as our base class for any future &#8220;class associated with a\nwindow&#8221; work.\nThe only derived class for now is the <code>RootWindow<\/code>,\nthe top-level frame window that for now is the only window that the\nprogram uses.\nAs you may suspect, we may have other derived classes later\nas the need arises.\n<\/p>\n<p>\nThe reason why the <code>WinRegisterClass<\/code> method is\nvirtual (and doesn&#8217;t do anything interesting) is so that\na derived class can modify the <code>WNDCLASS<\/code> that is\nused when the class is registered.\nI don&#8217;t have any immediate need for it, but it&#8217;ll be there if I need it.\n<\/p>\n<p>\nWe use the <code>GWLP_USERDATA<\/code> window long to store\nthe pointer to the associated class,\nthereby allowing us to recover the object from the window handle.\n<\/p>\n<p>\nObserve that in the\n<code>RootWindow::HandleMessage<\/code> method, I used the\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/vccelng\/htm\/key_s-z_1.asp\">\nVisual C++ __super extension<\/a>.\nIf you don&#8217;t want to rely on a nonstandard extension, you can\ninstead write\n<\/p>\n<pre>\nclass RootWindow : public Window\n{\npublic:\n <font COLOR=\"blue\">typedef Window super;<\/font>\n ...\n<\/pre>\n<p>\nand use <code>super<\/code> instead of <code>__super<\/code>.\n<\/p>\n<p>\nThis program doesn&#8217;t do anything interesting;\nit&#8217;s just going to be a framework for future samples.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I think it&#8217;s time to update the scratch program we&#8217;ve been using for the past year. I hear there&#8217;s this new language called C++ that&#8217;s going to become really popular any day now, so let&#8217;s hop on the bandwagon! #define STRICT #define UNICODE #define _UNICODE #include &lt;windows.h&gt; #include &lt;windowsx.h&gt; #include &lt;ole2.h&gt; #include &lt;commctrl.h&gt; #include &lt;shlwapi.h&gt; [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-35813","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>I think it&#8217;s time to update the scratch program we&#8217;ve been using for the past year. I hear there&#8217;s this new language called C++ that&#8217;s going to become really popular any day now, so let&#8217;s hop on the bandwagon! #define STRICT #define UNICODE #define _UNICODE #include &lt;windows.h&gt; #include &lt;windowsx.h&gt; #include &lt;ole2.h&gt; #include &lt;commctrl.h&gt; #include &lt;shlwapi.h&gt; [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/35813","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=35813"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/35813\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=35813"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=35813"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=35813"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}