{"id":177,"date":"2007-12-12T19:35:37","date_gmt":"2007-12-12T18:35:37","guid":{"rendered":"http:\/\/blog.m-ri.de\/index.php\/2007\/12\/12\/die-unsitte-immer-getmodulehandlenull-fuer-hinstance-in-createwindow-und-registerclass-zu-verwenden\/"},"modified":"2011-03-30T18:06:04","modified_gmt":"2011-03-30T17:06:04","slug":"die-unsitte-immer-getmodulehandlenull-fuer-hinstance-in-createwindow-und-registerclass-zu-verwenden","status":"publish","type":"post","link":"http:\/\/blog.m-ri.de\/index.php\/2007\/12\/12\/die-unsitte-immer-getmodulehandlenull-fuer-hinstance-in-createwindow-und-registerclass-zu-verwenden\/","title":{"rendered":"Die Unsitte immer GetModuleHandle(NULL) f\u00fcr hInstance in CreateWindow und RegisterClass zu verwenden"},"content":{"rendered":"<p>Carsten hat mich dazu inspiriert noch ein wenig mehr Don Quichotte zu spielen und gegen Windm\u00fchlen zu k\u00e4mpfen: Damit hier mein zweiter Beitrag zum Thema <em>Unsitten<\/em>.<\/p>\n<p>Der hInstance Parameter in <em>CreateWindow(Ex) <\/em>und <em>RegisterClass (WNDCLASS) <\/em>wird oft genug nicht verstanden. Man braucht f\u00fcr diese Funktionen einen\u00a0HINSTANCE Wert. Den hat aber niemand in der Tasche, wenn man mit der Win32 API pur mal eben so ein Programm schreibt.\u00a0Die wenigsten kommen auf die Idee den <em>hInstance <\/em>Wert aus <em>WinMain <\/em>und <em>DllMain <\/em>irgendwo global zu speichern und zu verwenden. Globals sind ja irgendwie &#8222;b\u00f6se&#8220;, und nicht OOP-like&#8230; \ud83d\ude09<\/p>\n<p>Was also tun? Irgendein Unwissender empfiehlt einfach <em>GetModuleHandle(NULL)<\/em> zu verwenden und seit dem dieser Unwissende diesen Tipp in die Welt gesetzt hat kursiert er durch die Foren&#8230; unaufhaltsam&#8230;<\/p>\n<p>\u2757 Das Problem: Es geht&#8230; manchmal&#8230; aber portabel ist der Code damit nicht und man erlebt eigent\u00fcmliche Sachen damit an anderer Stelle unter annderen (DLL-)Umst\u00e4nden. Aber warum?<\/p>\n<p>Das Geheimnis steckt darin, dass Fensterklassen nicht einfach so unter ihrem Namen abgelegt werden, sondern unter einem Namen <strong><em>und<\/em> <\/strong>der hInstance, die bei <em>RegisterClass <\/em>mit angegeben wird. So hat jeder Prozess seine Liste der Fensterklassen die aus <em>hInstance <\/em>und dem Namen der Klasse bestehen. Auch die Standard Fensterklassen wie <em>Edit, Button, Static<\/em> etc. werden mit der hInstance der <em>User32.dll <\/em>gespeichert.<\/p>\n<p>Wird nun ein Fenster erzeugt mit <em>CreateWindow(Ex)<\/em>, dann benutzt der Windowsmanager die Kombination aus <em>hInstance <\/em>Wert,\u00a0der bei <em>CreateWindow(Ex) <\/em>angegeben wird und dem Namen der Klasse um den entsprechenden Klassen Eintrag zu finden.<\/p>\n<p>Es ist also vollkommen OK wenn DLLs selber Klassen registrieren mit ein und unterschiedliche Module den selben Namen verwenden. Da gibt es keinen Konflikt, denn durch die <em>hInstance <\/em>Werte bleiben die Klassen eineindeutig. Und auch jede DLL kann damit, dass von Ihr gew\u00fcnschte Fenster mit der entsprechenden Klasse erzeugen, denn jede DLL hat eine unterschiedliche <em>hInstance<\/em>.<\/p>\n<p>Einzige Ausnahme ist eine Klasse, die mit dem Klassenstil <em>CS_GLOBALCLASS<\/em> registriert wird. Bei solch einer Klasse wird der Windowsmanager nur auf den Namen und nicht auf den Wert der <em>hInstance <\/em>achten. Jedem wird klar sein, dass die Standardfensterklassen der <em>USER32.DLL<\/em> und auch die Klassen der <em>COMCTL32.DLL <\/em>mit diesem Stil registriert wurden.<br \/>\nUnd klar ist auch, dass man seine eigenen Klassen, die in DLLs liegen mit diesem Flag <em>CS_GLOBALCLASS<\/em> registrieren muss, wenn man diese Klassen applikationsweit verwenden will. W\u00fcrde man also ein Dialogtemplate mit einer eigenen Klasse anlegen, die in einer DLL liegt, so kann der Dialogmanager, der wieder <em>hInstance<\/em> der Applikation verwendet, die entsprechende Klasse nicht finden, wenn diese nicht mit <em>CS_GLOBALCLASS<\/em> registriert wurde.<\/p>\n<p>Es ist und bleibt eine Unsitte <em>GetModuleHandle(NULL) <\/em>beim Registrieren der Windowsklasse zu verwenden, denn dieses hInstance, das man erh\u00e4lt ist nat\u00fcrlich das hInstance der Applikation, und nicht das des Modules, welches die Klasse enth\u00e4lt, z.B. eben eine DLL. Es wundert nicht wenn man etwas sp\u00e4ter seine Klassen in eine DLL auslagert erstaunt feststellt, dass auf einmal die Sachen nicht mehr funktionieren wie sie sollen.<\/p>\n<p>Um solchen Problemen aus dem Weg zu gehen sollte man immer das <em>hInstance <\/em>verwenden, das zu dem entsprechenden Modul geh\u00f6rt. Diesen Wert erh\u00e4lt man durch <em>WinMain <\/em>oder <em>DllMain<\/em>. Am Besten man speichert diesen in einer globalen Variablen. Die MFC hat hierzu eine spezielle Funktion <em>AfxGetInstanceHandle<\/em>, die dies f\u00fcr das entsprechende Modul erledigt. Aber ein MFC Programmierer w\u00fcrde ja auch <em>AfxRegisterClass <\/em>verwenden und nicht in diese Probleme laufen, wiederum vorausgesetzt er verwendet auch brav <em>AFX_MANAGE_STATE<\/em> \ud83d\ude42<\/p>\n<p>\u2757 Anmerkung: Es gibt auch Code, der einem erlaubt das hInstance Handle zu einem Code Abschnitt zu bestimmen.<br \/>\n<a href=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/10\/25\/247180.aspx\">http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/10\/25\/247180.aspx<\/a> (sofern man einen MS-Linker verwendet)<\/p>\n<p>Auch der folgende etwas trickreichere Code ist einen Blick wert:<\/p>\n<pre lang=\"cpp\">HINSTANCE Get_hInstance()\r\n{\r\n\u00a0MEMORY_BASIC_INFORMATION mbi;\u00a0\r\n\u00a0VirtualQuery(Get_hInstance, &amp;mbi, sizeof(mbi));\u00a0\r\n\u00a0return reinterpret_cast&lt;HINSTANCE&gt;(mbi.AllocationBase);\u00a0\r\n}<\/pre>\n<p>Aber bitte diesen Code nicht in eine DLL auslagern <img src=\"http:\/\/blog.m-ri.de\/wp-includes\/images\/smilies\/mrgreen.png\" alt=\":mrgreen:\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Carsten hat mich dazu inspiriert noch ein wenig mehr Don Quichotte zu spielen und gegen Windm\u00fchlen zu k\u00e4mpfen: Damit hier mein zweiter Beitrag zum Thema Unsitten. Der hInstance Parameter in CreateWindow(Ex) und RegisterClass (WNDCLASS) wird oft genug nicht verstanden. Man braucht f\u00fcr diese Funktionen einen\u00a0HINSTANCE Wert. Den hat aber niemand in der Tasche, wenn man &hellip; <a href=\"http:\/\/blog.m-ri.de\/index.php\/2007\/12\/12\/die-unsitte-immer-getmodulehandlenull-fuer-hinstance-in-createwindow-und-registerclass-zu-verwenden\/\" class=\"more-link\"><span class=\"screen-reader-text\">\u201eDie Unsitte immer GetModuleHandle(NULL) f\u00fcr hInstance in CreateWindow und RegisterClass zu verwenden\u201c <\/span>weiterlesen<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[30,4,3,2],"tags":[370,74,61],"class_list":["post-177","post","type-post","status-publish","format-standard","hentry","category-c","category-mfc","category-programmieren","category-windows-api","tag-c","tag-unsitten","tag-winapi"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/177","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/comments?post=177"}],"version-history":[{"count":0,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/177\/revisions"}],"wp:attachment":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/media?parent=177"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/categories?post=177"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/tags?post=177"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}