{"id":112447,"date":"2026-06-19T07:00:00","date_gmt":"2026-06-19T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=112447"},"modified":"2026-06-20T00:02:34","modified_gmt":"2026-06-20T07:02:34","slug":"20260619-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260619-00\/?p=112447","title":{"rendered":"What does it mean when the bottom bit of my <CODE>HMODULE<\/CODE> is set?"},"content":{"rendered":"<p>The numeric value of an <code>HMODULE<\/code> is normally the base address of the DLL or EXE it represents. These base addresses are <a title=\"Why is address space allocation granularity 64KB?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20031008-00\/?p=42223\"> always multiples of 64KB<\/a>, so the bottom 16 bits are all zero. Yet you may run across one with the bottom bit set. What does that mean?<\/p>\n<p>Normally, when you load a DLL, it gets an entry in the table of loaded modules. This table is consulted by functions like <code>Get\u00adModule\u00adHandle<\/code> and <code>Enum\u00adProcess\u00adModules<\/code> to identify all the DLLs that have been loaded. It also is used to keep track of how many times each DLL has been loaded, so that the DLL is removed from memory when the correct number of <code>Free\u00adLibrary<\/code> calls has been made.<\/p>\n<p>Many of the flags to the <code>Load\u00adLibrary\u00adEx<\/code> function alter how the system locates the DLL to load, but some of them alter how the DLL is itself loaded into memory. The interesting one here is the <code>LOAD_<wbr \/>LIBRARY_<wbr \/>AS_<wbr \/>DATAFILE<\/code> flag.<\/p>\n<p>If you ask that a DLL be loaded as a data file, and there isn&#8217;t already a copy of the DLL loaded normally, then the loader will search the file system for the DLL in the manner described by the other flags, and then it will just map the DLL into memory without doing any of the usual stuff like applying fixups, and then returns you an <code>HMODULE<\/code> that represents the location where the DLL was mapped into memory, but it also sets the bottom bit as a note to itself to say &#8220;This wasn&#8217;t loaded the normal way.&#8221;<\/p>\n<p>If the loader decides to map the DLL into memory directly, then the DLL does not get an entry in the list of loaded modules. While the module was loaded in a strict sense of the term, it was not loaded as a <i>functional<\/i> module. The code is not ready to execute: Its dependencies were not resolved. Its initialization was not run. It&#8217;s just a bunch of bytes mapped into memory. If you call <code>Get\u00adModule\u00adHandle<\/code> or <code>Enum\u00adProcess\u00adModules<\/code>, the module won&#8217;t show up because those functions use the list of &#8220;properly&#8221; loaded modules, and your datafile DLL wasn&#8217;t put on that list.<\/p>\n<p>Functions like <code>Find\u00adResource<\/code> recognize these &#8220;not really a module&#8221; modules. For example, if you ask to find a resource in a loaded-as-datafile module, the <code>Find\u00adResource<\/code> function knows that it has to convert RVAs in the PE header into physical file offsets.<\/p>\n<p>And when you pass the <code>HMODULE<\/code> back to <code>Free\u00adLibrary<\/code>, it sees that the bottom bit is set and knows, &#8220;Oh, this was never entered into the module list, so I don&#8217;t have to remove it from the module list either.&#8221;<\/p>\n<p>This special behavior of the bottom bit is locked into the ABI thanks to this macros provided in the <code>Load\u00adLibrary\u00adEx<\/code> documentation:<\/p>\n<pre>#define LDR_IS_DATAFILE(handle)      (((ULONG_PTR)(handle)) &amp; (ULONG_PTR)1)\r\n<\/pre>\n<p>I don&#8217;t know if this use of the bottom bit was intended to be an implementation detail, or whether documenting it was an intentional decision, but what&#8217;s done is done, and it&#8217;s documented, so it&#8217;s too late to change it now.<\/p>\n<p><b>Bonus chatter<\/b>: You can see in the documentation another macro that reveals that the second-from-bottom bit is also used as a special signal:<\/p>\n<pre>#define LDR_IS_IMAGEMAPPING(handle)  (((ULONG_PTR)(handle)) &amp; (ULONG_PTR)2)\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>A special kind of <CODE>HMODULE<\/CODE>.<\/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-112447","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>A special kind of <CODE>HMODULE<\/CODE>.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112447","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=112447"}],"version-history":[{"count":1,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112447\/revisions"}],"predecessor-version":[{"id":112448,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112447\/revisions\/112448"}],"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=112447"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=112447"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=112447"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}