{"id":38,"date":"2007-03-06T19:08:45","date_gmt":"2007-03-06T18:08:45","guid":{"rendered":"http:\/\/blog.m-ri.de\/index.php\/2007\/03\/06\/createstreamonhglobal-und-globalalloc\/"},"modified":"2007-03-06T19:11:10","modified_gmt":"2007-03-06T18:11:10","slug":"createstreamonhglobal-und-globalalloc","status":"publish","type":"post","link":"http:\/\/blog.m-ri.de\/index.php\/2007\/03\/06\/createstreamonhglobal-und-globalalloc\/","title":{"rendered":"CreateStreamOnHGlobal und GlobalAlloc"},"content":{"rendered":"<p>Man k\u00f6nnte diesen Artikel auch den folgenden Titel <em>&#8222;Was passieren kann, wenn man die Dokumentation nicht richtig liest!&#8220;<\/em> geben. \ud83d\ude08<\/p>\n<p>Dieser Code<\/p>\n<p class=\"ccode\">HGLOBAL\u00a0hMem = ::GlobalAlloc(GMEM_MOVEABLE,iMaximumSize);<br \/>\nif (!hMem)<br \/>\n\u00a0\u00a0\u00a0 AfxThrowMemoryException();<br \/>\nLPVOID pImage = ::GlobalLock(hMem);<br \/>\nint iSize = FillBufferWithData(pImage);<br \/>\n::GlobalUnlock(hMem);<br \/>\nCComPtr&lt;IStream&gt; spStream;<br \/>\nHRESULT hr = ::CreateStreamOnHGlobal(hMem,FALSE,&amp;spStream);<br \/>\nif (SUCCEEDED(hr))<br \/>\n{<br \/>\n\u00a0\u00a0\u00a0 \/\/ Limit the stream to its real size<br \/>\n\u00a0\u00a0\u00a0 ULARGE_INTEGER ulSize;<br \/>\n\u00a0\u00a0\u00a0 ulSize.QuadPart = iSize;<br \/>\n\u00a0\u00a0\u00a0 VERIFY(SUCCEEDED(spStream-&gt;SetSize(ulSize)));<br \/>\n\u00a0\u00a0\u00a0 \/\/ Do whatever has to be done<br \/>\n\u00a0\u00a0 DoSomethingWithStream(spStream);<br \/>\n}<br \/>\n\/\/ Release Stream<br \/>\nspStream = NULL;<br \/>\n\/\/ Free memory WITH A RANDOM CRASH<br \/>\n::GobalFree(hMem);<\/p>\n<p>sieht ganz normal aus. Eigent\u00fcmlicher Weise passiert es manchmal, genauer gesagt recht selten, dass der <em>GlobalFree<\/em> fehlschl\u00e4gt. Der <em>Application Verifier <\/em>meldet einen inkorrekten Heap Block. Aber wie das. Der Block wird mit <em>GlobalAlloc<\/em> allokiert an <em>CreateStreamOnHGlobal<\/em> \u00fcbergeben und freigegeben nachdem der Stream entsorgt wurde.<\/p>\n<p>Was ist die Ursache f\u00fcr das Problem? Nach einigem Pr\u00fcfen und Tests kam ich dahinter, dass offensichtlich nach einer Reallocation des Speichers mein Heap-Block ung\u00fcltig wird.<br \/>\nErstaunlich ist, dass <em>SetSize<\/em> hier nicht den Speicherbedarf vergr\u00f6\u00dfert sondern nur den Stream auf die korrekte Gr\u00f6\u00dfe verkleinert! Dennoch&#8230; unter bestimmten Umst\u00e4nden wird hier eine Reallocation vorgenommen.<br \/>\nAlles Rumexperimentieren n\u00fctzt nichts. Der Fehler oder das Problem in diesem St\u00fcck Code wird auch nicht vom stundenlangen Ansehen und Debuggen nicht klarer.<\/p>\n<p>Also nochmal richtig <a href=\"http:\/\/msdn2.microsoft.com\/en-us\/aa378980.aspx\" title=\"CreateStreamOnHGlobal Doku\">RTFM (Read the fine MSDN)<\/a> und dort finden wir diesen netten Absatz:<br \/>\n<em>hGlobal [in] Memory handle allocated by the GlobalAlloc function. The handle must be allocated as \u27a1 <strong>movable <\/strong>and nondiscardable.<\/em><\/p>\n<p>Und nun wird klar wo der Fehler liegt. Der Speicherblock der mit <em>GMEM_FIXED<\/em> alloziert wurde kann nicht realloziert und vergr\u00f6\u00dfert werden. CreateStreamOnHGlobal reagiert nicht mit einem Fehler, wenn man den Block mit <em>GMEM_FIXED<\/em> allokiert. Aber das hat sp\u00e4ter evtl. einen sehr schwierig zu lokalisierenden Fehler zur Folge.<\/p>\n<p>Also flink die Allokation in <em>GMEM_MOVEABLE<\/em>\u00a0ge\u00e4ndert und siehe da. Das Handle bleibt erhalten, der <em>GlobalFree<\/em> schl\u00e4gt nicht mehr fehl.<\/p>\n<p>Die Dokumentation ist an dieser Stelle aber auch wirklich nicht sehr auff\u00e4llig. \ud83d\ude10<br \/>\nDeshalb habe ich einen Verbesserungsvorschlag dazu gemacht:<br \/>\n<a href=\"https:\/\/connect.microsoft.com\/VisualStudio\/feedback\/ViewFeedback.aspx?FeedbackID=260866\">https:\/\/connect.microsoft.com\/VisualStudio\/feedback\/ViewFeedback.aspx?FeedbackID=260866<\/a><\/p>\n<p>Anmerkung: Der Urspr\u00fcngliche Code verwendete <em>CHeapPtr&lt;BYTE,CGlobalAllocator&gt;<\/em>, weil ich es liebe wenn Destruktoren aufr\u00e4umen.\u00a0Der <em>CGlobalAllocator <\/em>verwendet auch immer GMEM_FIXED, was das ganze noch etwas un\u00fcbersichtlicher gemacht hat, denn wer denkt schon dran wie eine solche Wrapper-Klasse Speicher allokiert.<\/p>\n<p>BTW: Auch hier f\u00fchrte der <em><a href=\"http:\/\/blog.m-ri.de\/index.php\/2007\/03\/02\/der-application-verifier-mein-neuer-freund\/\">Application Verifier<\/a> <\/em>auf die korrekte Spur.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Man k\u00f6nnte diesen Artikel auch den folgenden Titel &#8222;Was passieren kann, wenn man die Dokumentation nicht richtig liest!&#8220; geben. \ud83d\ude08 Dieser Code HGLOBAL\u00a0hMem = ::GlobalAlloc(GMEM_MOVEABLE,iMaximumSize); if (!hMem) \u00a0\u00a0\u00a0 AfxThrowMemoryException(); LPVOID pImage = ::GlobalLock(hMem); int iSize = FillBufferWithData(pImage); ::GlobalUnlock(hMem); CComPtr&lt;IStream&gt; spStream; HRESULT hr = ::CreateStreamOnHGlobal(hMem,FALSE,&amp;spStream); if (SUCCEEDED(hr)) { \u00a0\u00a0\u00a0 \/\/ Limit the stream to its real &hellip; <a href=\"http:\/\/blog.m-ri.de\/index.php\/2007\/03\/06\/createstreamonhglobal-und-globalalloc\/\" class=\"more-link\"><span class=\"screen-reader-text\">\u201eCreateStreamOnHGlobal und GlobalAlloc\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":[11,3,2],"tags":[370,61],"class_list":["post-38","post","type-post","status-publish","format-standard","hentry","category-debugging","category-programmieren","category-windows-api","tag-c","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\/38","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=38"}],"version-history":[{"count":0,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/38\/revisions"}],"wp:attachment":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/media?parent=38"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/categories?post=38"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/tags?post=38"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}