{"id":14943,"date":"2010-02-15T07:00:00","date_gmt":"2010-02-15T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2010\/02\/15\/private-classes-superclassing-and-global-subclassing\/"},"modified":"2010-02-15T07:00:00","modified_gmt":"2010-02-15T07:00:00","slug":"private-classes-superclassing-and-global-subclassing","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20100215-00\/?p=14943","title":{"rendered":"Private classes, superclassing, and global subclassing"},"content":{"rendered":"<p>\nIn the suggestion box,\n<a HREF=\"http:\/\/cs.usu.edu.ru\/home\/skrobov\/\">A. Skrobov<\/a>\nasks\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/pages\/407234.aspx#769058\">\nwhy it&#8217;s impossible to superclass <code>WC_DIALOG<\/code><\/a>,\nbut the example that follows is not actually superclassing.\n<\/p>\n<blockquote CLASS=\"q\"><p>\nWhen I register my own class under this atom,\nand leave NULL in WNDCLASS.hInstance, Windows fills it in for me.\nThen I have two distinct classes registered:\n(0,WC_DIALOG) and (hMyInstance,WC_DIALOG),\nand DialogBox functions all use the first one.\n<\/p><\/blockquote>\n<p>\nThis question is a bit confused,\nsince it says that the goal is to superclass the dialog class,\nbut registering <code>WC_DIALOG<\/code> is not superclassing.\n<\/p>\n<p>\nFirst, I&#8217;ll refer everyone to\n<a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms997565.aspx\">\nthis MSDN article which describes the various ways of\nmanipulating a window class<\/a>:\nSubclassing, superclassing, and global subclassing.\n<\/p>\n<p>\nTo superclass the dialog class, you retrieve information\nabout the class by calling <code>GetClassInfo<\/code>\nand then register a <i>new<\/i> class based on the original\nclass.\nBut you don&#8217;t need to go to all that effort to superclass\nthe dialog class,\nbecause you already know what you need to know:\nThe number of extra bytes is <code>DLGWINDOWEXTRA<\/code>,\nand the dialog procedure is <code>DefDlgProc<\/code>.\nYou can just\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2003\/11\/13\/55662.aspx\">\nregister your superclass directly<\/a>,\nas we saw last time.\n<\/p>\n<p>\nSuperclassing is done by registering your custom class under\na different name, and using that class name if you want to obtain\nthe new behavior.\nOn the other hand, the question about talks about registering\na class under the same name as the original (namely, <code>WC_DIALOG<\/code>).\nThis isn&#8217;t subclassing, nor is it superclassing,\nnor is it even global subclassing.\n<\/p>\n<p>\nBefore continuing the discussion, I&#8217;ll first address the\nissue of leaving <code>NULL<\/code> in <code>WNDCLASS.hInstance<\/code>:\nThe value <code>NULL<\/code> for the instance handle\nis not legal when registering a class.\nEach class is associated with a module instance,\nand <code>NULL<\/code> is not a module instance.\nThe window manager autocorrects this mistake by registering\nthe class under the module corresponding to the executable.\nThis is the same special-case behavior you get if you call\n<code>GetModuleHandle(NULL)<\/code>,\nso it&#8217;s not something completely out of the blue.\nIt looks like A. Skrobov is being confused by\nthe window manager&#8217;s attempt to <i>do what you mean<\/i>.\nSo much for being helpful.\n<\/p>\n<p>\nOkay, back to the original problem.\nRecall that\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/04\/18\/409205.aspx\">\nthe <code>HINSTANCE<\/code> member of the\n<code>WNDCLASS<\/code> structure\nis used to specify the class namespace<\/a>.\nIf you register a class against the handle of the current\nexecutable, then in order to create a window with that class,\nyou need to create it with that same instance handle.\n<\/p>\n<p>\nNow we can put all the pieces together:\nRegistering the class with <code>WNDCLASS.hInstance = NULL<\/code>\nis autocorrected to registering it with\n<code>WNDCLASS.hInstance = GetModuleHandle(NULL)<\/code>,\nwhich places the class in the window class namespace of\nthe current module.\nThis is a separate class from the system dialog class,\nwhich is registered against <code>GetModuleHandle(TEXT(\"USER32\"))<\/code>.\nThe two are registered against different modules,\nso they live independent lives.\nThey just happen to have\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2008\/10\/21\/9008384.aspx\">\nthe same name<\/a>.\n<\/p>\n<p>\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/04\/18\/409205.aspx\">\nAs we learned a few years ago<\/a>,\nthe instance handle you pass to the <code>CreateWindow<\/code> (or\nrelated) function\nis used to look up the window class,\nand as we also learned,\nthe <code>HINSTANCE<\/code> you pass to the <code>DialogBox<\/code>\n(or related) function\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/03\/29\/403298.aspx\">\nis used to look up the template<\/a>\nas well as to\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/03\/30\/403711.aspx\">\ncreate the frame window<\/a>.\nThe class name comes from the template, and if you didn&#8217;t\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/06\/21\/161375.aspx\">\nspecify an explicit class in your template<\/a>,\nthen the dialog manager will use <code>WC_DIALOG<\/code>.\n<\/p>\n<p>\nYou now have all the pieces necessary to understand what is going on.\nWhen you register the class against your executable&#8217;s instance,\nyou need to use that same instance when creating the dialog box\nso that your private class is found instead of the global one.\n<\/p>\n<p>\nTo show how this all fits together,\nI&#8217;ve written a little program which registers a private class\nwhich happens to have the name <code>WC_DIALOG<\/code>\nand then uses it to create a dialog box.\n<\/p>\n<pre>\n\/\/ scratch.rc\n#include &lt;windows.h&gt;\n\/\/ A pointless dialog box, for illustration only\n1 DIALOG 0,0,150,50\nSTYLE DS_MODALFRAME | DS_SHELLFONT | WS_POPUP | WS_VISIBLE |\n    WS_CAPTION | WS_SYSMENU\nCAPTION \"Pointless\"\nFONT 8, \"MS Shell Dlg\"\nBEGIN\n    DEFPUSHBUTTON \"Cancel\",IDCANCEL,50,18,50,14\nEND\n\/\/ scratch.cpp\n#include &lt;windows.h&gt;\nLRESULT CALLBACK\nSuperDlgProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)\n{\n  switch (uiMsg) {\n  case WM_ERASEBKGND:\n    return DefWindowProc(hwnd, uiMsg, wParam, lParam);\n  }\n  return DefDlgProc(hwnd, uiMsg, wParam, lParam);\n}\nINT_PTR CALLBACK\nDlgProc(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)\n{\n  switch (wm) {\n  case WM_INITDIALOG: return TRUE;\n  case WM_CLOSE: EndDialog(hwnd, 0); return TRUE;\n  }\n  return FALSE;\n}\nint CALLBACK\nWinMain(HINSTANCE hinst, HINSTANCE hinstPrev,\n        LPSTR pszCmdLine, int nShowCmd)\n{\n  WNDCLASS wc;\n  wc.style = 0;\n  wc.lpfnWndProc = SuperDlgProc;\n  wc.cbClsExtra = 0;\n  wc.cbWndExtra = DLGWINDOWEXTRA;\n  wc.hInstance = hinst;\n  wc.hIcon = NULL;\n  wc.hCursor = LoadCursor(NULL, IDC_ARROW);\n  wc.hbrBackground = (HBRUSH)(COLOR_INFOBK + 1);\n  wc.lpszMenuName = NULL;\n  wc.lpszClassName = WC_DIALOG;\n  if (RegisterClass(&amp;wc))\n    DialogBox(hinst, MAKEINTRESOURCE(1), NULL, DlgProc);\n  return 0;\n}\n<\/pre>\n<p>\nThe dialog template is itself entirely unremarkable;\nit looks like any old dialog template.\n<\/p>\n<p>\nOur superclass takes the regular dialog box class and\ngives it a custom background color,\nnamely <code>COLOR_INFOBK<\/code>.\n<\/p>\n<p>\nThe program registers this private version of <code>WC_DIALOG<\/code>\nand creates a dialog box based on it.\nSince we passed the same <code>HINSTANCE<\/code> in the\n<code>WNDCLASS.hInstance<\/code> as we did to\n<code>DialogBox<\/code>,\nthe lookup of the <code>WC_DIALOG<\/code> class will\nfind our private version and use it instead of the global version.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the suggestion box, A. Skrobov asks why it&#8217;s impossible to superclass WC_DIALOG, but the example that follows is not actually superclassing. When I register my own class under this atom, and leave NULL in WNDCLASS.hInstance, Windows fills it in for me. Then I have two distinct classes registered: (0,WC_DIALOG) and (hMyInstance,WC_DIALOG), and DialogBox functions [&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-14943","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>In the suggestion box, A. Skrobov asks why it&#8217;s impossible to superclass WC_DIALOG, but the example that follows is not actually superclassing. When I register my own class under this atom, and leave NULL in WNDCLASS.hInstance, Windows fills it in for me. Then I have two distinct classes registered: (0,WC_DIALOG) and (hMyInstance,WC_DIALOG), and DialogBox functions [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/14943","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=14943"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/14943\/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=14943"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=14943"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=14943"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}