{"id":107926,"date":"2023-03-10T07:00:00","date_gmt":"2023-03-10T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107926"},"modified":"2023-03-10T09:20:06","modified_gmt":"2023-03-10T17:20:06","slug":"20230310-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230310-00\/?p=107926","title":{"rendered":"When should I use <CODE>CS_GLOBALCLASS<\/CODE>?"},"content":{"rendered":"<p>When you register a window class, one of the class styles is <code>CS_<wbr \/>GLOBAL\u00adCLASS<\/code>. When should you use this style?<\/p>\n<p>The documentation says that the <code>CS_<wbr \/>GLOBAL\u00adCLASS<\/code> style creates an <a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/win32\/winmsg\/about-window-classes#application-global-classes\"> application global class<\/a>, which is a window class that is available to all other modules in the process.<\/p>\n<p>Specifically, it means that anybody in the process can call <code>Create\u00adWindow<\/code> with your class name and summon your window class, even if they get the <code>HINSTANCE<\/code> wrong.<\/p>\n<p>Recall that <a title=\"What is the HINSTANCE passed to CreateWindow and RegisterClass used for?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050418-59\/?p=35873\"> window classes are looked up by the pair (<code>HINSTANCE<\/code>, class name)<\/a>. The purpose of the <code>HINSTANCE<\/code> is to give each module its own private namespace, so that one DLL&#8217;s <code>MyWindow<\/code> doesn&#8217;t collide with another DLL&#8217;s <code>MyWindow<\/code>. In order to create a window, you must specify both the <code>HINSTANCE<\/code> and the class name.<\/p>\n<p>If a class is registered as a &#8220;global class&#8221;, then it becomes possible to create a window of that class even if the <code>HINSTANCE<\/code> does not match. The primary audience for this is control libraries: If a control library registers its controls as global, then the controls can be created from a client DLL&#8217;s dialog template: When a dialog is created from a template, <a title=\"The dialog manager, part 2: Creating the frame window\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050330-00\/?p=36023\"> the <code>HINSTANCE<\/code> passed to the dialog box function is combined with the class name in the dialog template to create each window<\/a>. Normally, this means that you can create only controls that were registered to that <code>HINSTANCE<\/code>. But if the class cannot be found via (<code>HINSTANCE<\/code>, class name) lookup, then the system will look for a global class with the same class name. Registering your controls library controls as global classes therefore allows them to be created from any dialog template.<\/p>\n<p>Some people read that description and conclude, &#8220;Sounds like global classes are all upside, no downside, so I&#8217;ll register all of my classes as global classes.&#8221;<\/p>\n<p>But there <i>is<\/i> a downside. It&#8217;s the tragedy of the commons.<\/p>\n<p>If you decide to register all of your classes as global, then your classes are no longer scoped to your <code>HINSTANCE<\/code> and instead go into the list of global classes. Your <code>MyWindow<\/code> class, which you thought was private to your module, is now being exposed to all modules, and anybody can<\/p>\n<pre>HWND hwnd = CreateWindowW(L\"MyWindow\", L\"Any title\",\r\n    WS_CHILD | WS_BORDER,\r\n    x, y, width, height, parentWindow, nullptr,\r\n    <span style=\"border: solid 1px black;\">hinstAnything<\/span>, lpParam);\r\n<\/pre>\n<p>to create your window with an arbitrary <code>lpCreate\u00adParams<\/code>. The code that did this probably meant to create a window from their own <code>MyWindow<\/code> class, but they had a bug where they passed an incorrect <code>hinstAnything<\/code> (maybe the variable was uninitialized), and they ended up creating your window instead. You put your window class in the town square for anyone to use.<\/p>\n<p>Things get even worse if <i>two<\/i> people did this. Now you have two modules dumping their private business in the town square, and if both of them happen to choose the same name for a window class, the first one will register the global class successfully, and the second one will fail with <code>ERROR_<wbr \/>CLASS_<wbr \/>ALREADY_<wbr \/>EXISTS<\/code>. The second module will probably stop working at that point.<\/p>\n<p>Now, even if you register all your classes to your own <code>HINSTANCE<\/code>, other people can still create it if they have both the instance handle and the class name. You can document the class name in your library&#8217;s header file, and people can create it via <code>Create\u00adWindow<\/code>:<\/p>\n<pre>HINSTANCE hinstContoso = LoadLibraryW(L\"ContosoControls.dll\");\r\nHWND hwnd = CreateWindow(WC_CONTOSOGRID, L\"Grid title\",\r\n    WS_CHILD | CGS_GRIDLINES,\r\n    x, y, width, height, parentWindow, nullptr,\r\n    <span style=\"border: solid 1px black;\">hinstContoso<\/span>, lpParam);\r\n<\/pre>\n<p>You need <code>CS_<wbr \/>GLOBAL\u00adCLASS<\/code> only if you want outsiders to be able to create your control from a dialog template:<\/p>\n<pre>IDD_RESULTS DIALOG 32, 32, 160, 280\r\nCAPTION \"Query results\"\r\nBEGIN\r\n    CONTROL \"\", IDC_GRID, WC_CONTOSOGRID, CGS_GRIDLINES,\r\n            4, 4, 152, 272\r\nEND\r\n<\/pre>\n<p>In order to look up <code>IDD_<wbr \/>RESULTS<\/code>, the <code>HINSTANCE<\/code> must be the module that contains the dialog template. But that&#8217;s not the module that contains the registration for <code>WC_<wbr \/>CONTOSO\u00adGRID<\/code>. Registering <code>WC_<wbr \/>CONTOSO\u00adGRID<\/code> as a global class works around that problem.<\/p>\n<p>TL;DR: Use <code>CS_<wbr \/>GLOBAL\u00adCLASS<\/code> only for window classes that are intended to be created by others via dialog box templates.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When you want to be summoned from anywhere.<\/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-107926","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>When you want to be summoned from anywhere.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107926","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=107926"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107926\/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=107926"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107926"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107926"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}