{"id":37353,"date":"2004-11-09T06:57:00","date_gmt":"2004-11-09T06:57:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2004\/11\/09\/a-history-of-globallock-part-4-a-peek-at-the-implementation\/"},"modified":"2004-11-09T06:57:00","modified_gmt":"2004-11-09T06:57:00","slug":"a-history-of-globallock-part-4-a-peek-at-the-implementation","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20041109-00\/?p=37353","title":{"rendered":"A history of GlobalLock, part 4: A peek at the implementation"},"content":{"rendered":"<p><P>\nOn one of our internal discussion mailing lists, someone posted\nthe following question:\n<\/P>\n<BLOCKQUOTE CLASS=\"q\">\n<P>\nWe have some code that was using DragQueryFile to extract file paths.\nThe prototype for DragQueryFile appears as follows:\n<PRE>\nUINT DragQueryFile(\n    <FONT COLOR=\"red\">HDROP hDrop<\/FONT>,\n    UINT iFile,\n    LPTSTR lpszFile,\n    UINT cch\n);\n<\/PRE>\n<P>\nIn the code we have, instead of passing an HDROP as the first parameter,\nwe were passing in a pointer to a DROPFILES structure. This code was\nworking fine for the last few months until some protocol changes\nwe made in packet layouts over the weekend.\n<\/P>\n<P>\nI know that the bug is that we should be passing an HDROP handle\ninstead of a pointer, but I am just curious as to why this worked\nso flawlessly until now. In other words, what determines the\nvalidity of a handle and how come a pointer can sometimes\nbe used instead of a handle?\n<\/P>\n<\/BLOCKQUOTE>\n<P>\nGlobalLock accepts HGLOBALs that refer to either GMEM_MOVEABLE or GMEM_FIXED\nmemory. The rule for Win32 is that for fixed memory,\nthe HGLOBAL is itself a pointer to the memory,\nwhereas for moveable memory, the HGLOBAL is a handle that\nneeds to be converted to a pointer.\n<\/P>\n<P>\nGlobalAlloc works closely with GlobalLock so that GlobalLock can be fast.\nIf the memory happens to be aligned just right and pass some other\ntests, GlobalLock says &#8220;Woo-hoo, this is a handle to a GMEM_FIXED\nblock of memory, so I should just return the pointer back.&#8221;\n<\/P>\n<P>\nThe packet layout changes probably altered the alignment,\nwhich in turn caused GlobalLock no longer to recognize (mistakenly) the\ninvalid parameter as a GMEM_FIXED handle.  It then went down\nother parts of the validation path and realized that the handle\nwasn&#8217;t valid at all.\n<\/P>\n<P>\nThis is not, of course, granting permission to pass\nbogus pointers to GlobalLock; I&#8217;m just explaining why\nthe problem kicked up all of a sudden even though\nit has always been there.\n<\/P>\n<P>\nWith that lead-in, what&#8217;s the real story behind GMEM_MOVEABLE\nin Win32?\n<\/P>\n<P>\nGMEM_MOVEABLE memory allocates a &#8220;handle&#8221;.  This handle can be\nconverted to memory via GlobalLock.  You can call GlobalReAlloc()\non an unlocked GMEM_MOVEABLE block (or a locked GMEM_MOVEABLE\nblock when you pass the GMEM_MOVEABLE flag to GlobalReAlloc\nwhich means &#8220;move it even if it&#8217;s locked&#8221;) and the memory\n<STRONG>will move<\/STRONG>,\nbut the handle will continue to refer to it. You\nhave to re-lock the handle to get the new address it got moved to.\n<\/P>\n<P>\nGMEM_MOVEABLE is largely unnecessary; it provides additional\nfunctionality that most people have no use for.  Most people\ndon&#8217;t mind when Realloc hands back a different value from the\noriginal.  GMEM_MOVEABLE is primarily for the case where you\nhand out a memory handle, and then you decide to realloc it\nbehind the handle&#8217;s back.  If you use GMEM_MOVEABLE, the\nhandle remains valid even though the memory it refers to has moved.\n<\/P>\n<P>\nThis may sound like a neat feature, but in practice it&#8217;s much\nmore trouble than it&#8217;s worth.  If you decide to use moveable memory,\nyou have to lock it before accessing it, then unlock it when done.\nAll this lock\/unlock overhead becomes a real pain, since you can&#8217;t\nuse pointers any more.  You have to use handles and convert them\nto pointers right before you use them.\n(This also means no pointers into the middle of a moveable object.)\n<\/P>\n<P>\nConsequently, moveable memory is useless in practice.\n<\/P>\n<P>\nNote, however, that GMEM_MOVEABLE still lingers on in various\nplaces for compatibility reasons.  For example, clipboard data\nmust be allocated as moveable.\nIf you break this rule, some programs will crash\nbecause they made undocumented assumptions about how the\nheap manager internally manages handles to moveable memory blocks\ninstead of calling GlobalLock to convert the handle to a pointer.\n<\/P>\n<P>\nA very common error is forgetting to lock global handles before\nusing them.\nIf you forget and instead just cast a moveable memory handle to\na pointer, you will get strange results (and will likely corrupt the heap).\nSpecifically, global handles passed via\nthe <CODE>hGlobal<\/CODE> member of\n<A HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/com\/htm\/ost_a2z_9dt9.asp\">\nthe <CODE>STGMEDIUM<\/CODE> structure<\/A>,\nreturned via\n<A HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/winui\/winui\/windowsuserinterface\/dataexchange\/clipboard\/clipboardreference\/clipboardfunctions\/getclipboarddata.asp\">\nthe <CODE>GetClipboardData<\/CODE> function<\/A>,\nas well as lesser-known places like\nthe <CODE>hDevMode<\/CODE> and <CODE>hDevNames<\/CODE> members of\n<A HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/winui\/WinUI\/WindowsUserInterface\/UserInput\/CommonDialogBoxLibrary\/CommonDialogBoxReference\/CommonDialogBoxStructures\/PRINTDLG.asp\">\nthe <CODE>PRINTDLG<\/CODE> structure<\/A> are all potentially moveable.\nWhat&#8217;s scary is that if you make this mistake, you might actually get away\nwith it for a long time (if the memory you&#8217;re looking at happened to\nbe allocated as GMEM_FIXED), and then suddenly one day it crashes because\nall of a sudden somebody gave you memory that was allocated as\nGMEM_MOVEABLE.\n<\/P>\n<P>\nOkay, that&#8217;s enough about the legacy of the 16-bit memory manager for now.\nMy head is starting to hurt&#8230;\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>On one of our internal discussion mailing lists, someone posted the following question: We have some code that was using DragQueryFile to extract file paths. The prototype for DragQueryFile appears as follows: UINT DragQueryFile( HDROP hDrop, UINT iFile, LPTSTR lpszFile, UINT cch ); In the code we have, instead of passing an HDROP as the [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[2],"class_list":["post-37353","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>On one of our internal discussion mailing lists, someone posted the following question: We have some code that was using DragQueryFile to extract file paths. The prototype for DragQueryFile appears as follows: UINT DragQueryFile( HDROP hDrop, UINT iFile, LPTSTR lpszFile, UINT cch ); In the code we have, instead of passing an HDROP as the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/37353","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=37353"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/37353\/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=37353"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=37353"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=37353"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}