{"id":205,"date":"2008-02-25T21:38:01","date_gmt":"2008-02-25T20:38:01","guid":{"rendered":"http:\/\/blog.m-ri.de\/index.php\/2008\/02\/25\/warum-man-manchmal-afx_manage_state-auch-in-seiner-eigenen-exe-aufrufen-muss\/"},"modified":"2008-05-29T12:15:17","modified_gmt":"2008-05-29T10:15:17","slug":"warum-man-manchmal-afx_manage_state-auch-in-seiner-eigenen-exe-aufrufen-muss","status":"publish","type":"post","link":"http:\/\/blog.m-ri.de\/index.php\/2008\/02\/25\/warum-man-manchmal-afx_manage_state-auch-in-seiner-eigenen-exe-aufrufen-muss\/","title":{"rendered":"Warum man manchmal AFX_MANAGE_STATE auch in seiner eigenen EXE aufrufen muss"},"content":{"rendered":"<p><em>AFX_MANAGE_STATE <\/em>ist jedem bekannt, der mit DLLs hantiert. Es garantiert bei Verwendung der <em>MFC <\/em>DLLs, dass die entsprechenden Ressourcen bei den verschiedenen Ladeoperationen, wie z.B. <em>CString::LoadString <\/em>gefunden werden.<\/p>\n<p>Warum \u2753<br \/>\n<em>AfxSetResourceHandle <\/em>und <em>AfxGetResourceHandle <\/em>bedienen, eine globale Variable, die in der MFCn.DLL liegt.<br \/>\nGenau genommen ist es keine prozessglobale Variable, dies wird klar wenn man an Threads denkt. Die Variable wird threadlokal gespeichert.\u00a0 Die <em>HINSTANCE <\/em>f\u00fcr <em>AfxGetResourceHandle <\/em> liegt in einer Struktur, die <em>AFX_MODULE_STATE <\/em>hei\u00dft. In dieser Struktur werden noch einige andere wichtige threadlokale Daten gespeichert. Das sind z.B. f\u00fcr die Interaktion mit der Managed-World, der Activation\u00a0Context. Einen Blick auf den Inhalt dieser Struktur zu werfen lohnt sich.<br \/>\nDurch diese Struktur <em>AFX_MOUDLE_STATE <\/em>hat das Makro <em>AFX_MANAGE_STATE <\/em>seinen Namen.<\/p>\n<p>Gesetzt den Fall wir haben EXE und DLLs (egal ob Standard oder Extensions DLLs), die alle die <em>MFC <\/em>DLLs dynamisch binden, dann wird <em>AFX_MANAGE_STATE <\/em>wichtig. Ruft eine EXE also eine Funktion aus einer DLL auf, hat nat\u00fcrlich die EXE das entsprechende Handle an <em>AfxSetResourceHandle <\/em>\u00fcbergeben. Damit nun seinerseits die DLL eigene Ressourcen laden kann, wird durch <em>AFX_MANAGE_STATE <\/em>die alte <em>AFX_MODULE_STATE <\/em>Struktur gesichert (genau genommen der Zeiger darauf), und ein Zeiger auf die neue aktuelle <em>AFX_MODULE_STATE <\/em>Struktur gesetzt. <em>CString::LoadString <\/em>und <em>CDialog::DoModal <\/em>finden nun die richtigen Ressourcen in der DLL.<br \/>\nDer Destruktor sorgt nun am Ende der Funktion, dass der alte Zeiger der urspr\u00fcnglichen <em>AFX_MODULE_STATE <\/em>Struktur zur\u00fcckgesetzt wird, auf den Wert vor dem Aufruf.<\/p>\n<p>Soweit mal die Theorie \ud83d\ude42<br \/>\nWas passiert aber nun unter den folgenden Gegebenheiten:<\/p>\n<ul>\n<li>Eine DLL ruft einen Dialog oder eine MessageBox auf. In der EXE existieren Fenster, die einen Timer gesetzt haben?<\/li>\n<li>Oder eine DLL ruft einen Dialog auf, und die EXE hat einige COM-Objekte ver\u00f6ffentlicht, die nun von extern angesprochen werden k\u00f6nnen.<\/li>\n<li>Die DLL ruft \u00fcber einen Mechanismus eine Callback Funktion in der EXE auf.<\/li>\n<\/ul>\n<p>Das Alles ist kein Problem, solange nicht ihrerseits die Funktionen aus der EXE auf die Idee kommen eine Ressource zu laden. Was w\u00fcrde dann passieren?<\/p>\n<p>Klar, die <em>DLL <\/em>hat mit <em>AFX_MANAGE_STATE <\/em>den <em>AFX_MODULE_STATE <\/em>umgesetzt. W\u00fcrde die EXE in der Callback-Funktion oder Timer-Funktion nun selbst auf die Idee kommen einen Dialog zu laden oder nur einfach <em>CString::LoadString <\/em>auszuf\u00fchren, dann wird evtl. ein String oder Dialog geladen, aber vermutlich nicht der, den man erwartet.<br \/>\nVerwendet man nun Formatierungsfunktionen, wie z.B. Format, wird man manchmal b\u00f6se Wunder erleben. Oder man l\u00e4dt einen Dialog mit <em>DoModal<\/em>. Wenn man Gl\u00fcck hat ist der Dialog mit dieser ID nicht da und <em>DoModal <\/em>schl\u00e4gt fehl. Wenn man Pech hat wird der Dialog geladen, aber die entsprechenden Controls die gebunden werden oder mit <em>GetDlgItem <\/em>gesucht werden sind nicht vorhanden. Und da die meisten Entwickler keine Pr\u00fcfung auf <em>NULL <\/em>durchf\u00fchren (z.B. hier bei <em>GetDlgItem(IDC_MYITEM)-&gt;EnableWindow(FALSE)<\/em>) kracht es an den absonderlichsten Stellen.<br \/>\nAuch in der EXE ist man gut beraten in <em>OnTimer <\/em>Handlern <em>AFX_MANAGE_STATE <\/em>zu verwenden, wenn der Timer auch Ressourcen verwendet. Gleiches gilt in <em>COM <\/em>Interfaces oder <em>IDispatch <\/em>Interfaces. Gl\u00fccklicherweise sorgen hier die Wizards f\u00fcr korrektes Verhalten.<\/p>\n<p>Mehr noch: Ungl\u00fccklicherweise kann theoretisch jeder Windows Handler zu diesem Problem f\u00fchren, wenn diese Fensterfunktion direkt \u00fcber die modale Nachrichtenschleife\u00a0aus einer DLL aufgerufen wird.<br \/>\nUnd auch bei mancher Funktion, die als Callback aus einer DLL verwendet wird, kann ein zus\u00e4tzliches <em>AFX_MANAGE_STATE <\/em>nicht schaden.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>AFX_MANAGE_STATE ist jedem bekannt, der mit DLLs hantiert. Es garantiert bei Verwendung der MFC DLLs, dass die entsprechenden Ressourcen bei den verschiedenen Ladeoperationen, wie z.B. CString::LoadString gefunden werden. Warum \u2753 AfxSetResourceHandle und AfxGetResourceHandle bedienen, eine globale Variable, die in der MFCn.DLL liegt. Genau genommen ist es keine prozessglobale Variable, dies wird klar wenn man an &hellip; <a href=\"http:\/\/blog.m-ri.de\/index.php\/2008\/02\/25\/warum-man-manchmal-afx_manage_state-auch-in-seiner-eigenen-exe-aufrufen-muss\/\" class=\"more-link\"><span class=\"screen-reader-text\">\u201eWarum man manchmal AFX_MANAGE_STATE auch in seiner eigenen EXE aufrufen muss\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],"tags":[370,352],"class_list":["post-205","post","type-post","status-publish","format-standard","hentry","category-c","category-mfc","category-programmieren","tag-c","tag-mfc"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/205","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=205"}],"version-history":[{"count":0,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/205\/revisions"}],"wp:attachment":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/media?parent=205"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/categories?post=205"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/tags?post=205"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}