title: How do you properly implement (C++) thread local storage in a dynamically loaded DLL?
body: <p>In this case my dynamically loaded DLL is loaded by Windows Explorer in order to add a new propertysheet (new tab) to the file/folder properties page.</p>
  <p>A simple example of this is StrmExt.dll (<a href="http://download.microsoft.com/download/F/C/6/FC6943EB-790A-44AA-B32D-14ED7E22FD5D/NTFSExt.exe" rel="nofollow noreferrer">download source</a>). In this example (source provided by Microsoft) the DLL does NOT use thread local storage (TLS) and therefore causes major problems when loading multiple property pages at the same time.</p>
  <p>Upon reviewing the source the DLL required one thread-base variable (the file path of the file)...</p>
  <pre><code>static TCHAR g_szFile[MAX_PATH];
  </code></pre>
  <p>Changing this one line of code to:</p>
  <pre><code>_declspec (thread) TCHAR g_szFile[MAX_PATH];
  </code></pre>
  <p>... Enabled the DLL to support multiple threads and therefore multiple instances of the propertysheet. However, I knew this change would only be supported by Windows Vista and newer (tests on Windows 7 have been very positive). XP, for example, would not support this for a dynamically loaded library... And it is <a href="http://msdn.microsoft.com/en-us/library/2s9wt68x%28v=vs.80%29.aspx" rel="nofollow noreferrer">known to crash the application</a>. (See final paragraph).</p>
  <p>In order to run on XP I could not use this declaration. I suspected I needed to enhanced their DLL entry point from:</p>
  <pre><code>extern &quot;C&quot;
  BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
  {
      if (dwReason == DLL_PROCESS_ATTACH)
      {
          _Module.Init(ObjectMap, hInstance, &amp;LIBID_STRMEXTLib);
          DisableThreadLibraryCalls(hInstance);
      }
      else if (dwReason == DLL_PROCESS_DETACH)
          _Module.Term();
      return TRUE;    // ok
  }
  </code></pre>
  <p>...to something like this... As previously seen <a href="http://www.codeproject.com/Articles/2114/Simplify-the-Use-of-Thread-Local-Storage" rel="nofollow noreferrer">here</a></p>
  <pre><code>struct ThreadData {
      static TCHAR g_szFile[MAX_PATH];
  };
  ...
  DWORD g_dwThreadIndex;
  
  extern &quot;C&quot; BOOL WINAPI DllMain(HINSTANCE hInstance, 
                        DWORD dwReason, LPVOID /*pReserved*/)
  {
      ThreadData* pData;   
      switch (dwReason) {
          case DLL_PROCESS_ATTACH:
  
              g_dwThreadIndex = ::TlsAlloc();
              if (g_dwThreadIndex == TLS_OUT_OF_INDEXES)
                  return FALSE;
  
             // execute the DLL_THREAD_ATTACH code
  
          case DLL_THREAD_ATTACH:
  
              // allocate memory for this thread
              pData = (ThreadData*) ::LocalAlloc(LPTR, sizeof(ThreadData));
              if (pData == 0)
                  return FALSE;
  
              ::TlsSetValue(g_dwThreadIndex, (LPVOID) pData);
              break;
  
          case DLL_THREAD_DETACH:
  
              // release memory for this thread
              pData = (ThreadData*) ::TlsGetValue(g_dwThreadIndex);
              if (pData != 0)
                  ::LocalFree((HLOCAL) pData);
              break;
  
          case DLL_PROCESS_DETACH:
  
              // release memory for this thread
              pData = (ThreadData*) ::TlsGetValue(g_dwThreadIndex);
              if (pData != 0)
                  ::LocalFree((HLOCAL) pData);
              // release the TLS index
              ::TlsFree(g_dwThreadIndex);
              break;
      } 
      return TRUE;
  }
  </code></pre>
  <p>This works fine during the first load of the DLL whether I create 1 or 2 threads. After the DLL is freed Explorer crashes on the next load of the library.</p>
  <p>What am I misunderstanding? I noticed the original developer purposely disabled thread notification upon the DLL process attach notification. Why?</p>
  <pre><code>DisableThreadLibraryCalls(hInstance);
  </code></pre>