+<sect2>
+<title>Beware of DllMain()!</title>
+
+<para>The body of a <literal>DllMain()</literal> function is an
+extremely dangerous place! This is because the order in which DLLs are
+unloaded when a process is terminating is unspecified. This means that
+the <literal>DllMain()</literal> for your DLL may be called when other DLLs containing
+functions that you call when de-initializing your DLL have already
+been unloaded. In other words, you can't put shutdown code inside
+<literal>DllMain()</literal>, unless your shutdown code only requires use of certain
+functions which are guaranteed to be available (see the Platform SDK
+docs for more info).</para>
+
+<para>In particular, if you are writing a DLL that's statically
+linked with Haskell, it is not safe to call
+<literal>hs_exit()</literal> from <literal>DllMain()</literal>, since
+<literal>hs_exit()</literal> may make use of other DLLs (see also <xref
+ linkend="hs-exit" />). What's more, if you
+wait until program shutdown to execute your deinitialisation code, Windows will have
+terminated all the threads in your program except the one calling
+<literal>DllMain()</literal>, which can cause even more
+problems.</para>
+
+<para>A solution is to always export <literal>Begin()</literal> and <literal>End()</literal> functions from your
+DLL, and call these from the application that uses the DLL, so that
+you can be sure that all DLLs needed by any shutdown code in your
+End() function are available when it is called.</para>
+
+<para>The following example is untested but illustrates the idea (please let us
+ know if you find problems with this example or have a better one). Suppose we have a DLL called Lewis which makes use of 2
+Haskell modules <literal>Bar</literal> and <literal>Zap</literal>,
+where <literal>Bar</literal> imports <literal>Zap</literal> and is
+therefore the root module in the sense of <xref
+linkend="using-own-main" />. Then the main C++ unit for the DLL would
+look something like:</para>
+
+<programlisting>
+ // Lewis.cpp -- compiled using GCC
+ #include <Windows.h>
+ #include "HsFFI.h"
+
+ #define __LEWIS_DLL_EXPORT
+ #include "Lewis.h"
+
+ #include "Bar_stub.h" // generated by GHC
+ #include "Zap_stub.h"
+
+ BOOL APIENTRY DllMain( HANDLE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ ){
+ return TRUE;
+ }
+
+ extern "C"{
+
+ LEWIS_API HsBool lewis_Begin(){
+ int argc = ...
+ char *argv[] = ...
+
+ // Initialize Haskell runtime
+ hs_init(&argc, &argv);
+
+ // Tell Haskell about all root modules
+ hs_add_root(__stginit_Bar);
+
+ // do any other initialization here and
+ // return false if there was a problem
+ return HS_BOOL_TRUE;
+ }
+
+ LEWIS_API void lewis_End(){
+ hs_exit();
+ }
+
+ LEWIS_API HsInt lewis_Test(HsInt x){
+ // use Haskell functions exported by
+ // modules Bar and/or Zap
+
+ return ...
+ }
+
+ } // extern "C"
+
+and some application which used the functions in the DLL would have a main() function like:
+
+ // MyApp.cpp
+ #include "stdafx.h"
+ #include "Lewis.h"
+
+ int main(int argc, char *argv[]){
+ if (lewis_Begin()){
+ // can now safely call other functions
+ // exported by Lewis DLL
+
+ }
+ lewis_End();
+ return 0;
+ }
+</programlisting>
+
+<para><literal>Lewis.h</literal> would have to have some appropriate <literal>#ifndef</literal> to ensure that the
+Haskell FFI types were defined for external users of the DLL (who
+wouldn't necessarily have GHC installed and therefore wouldn't have
+the include files like <literal>HsFFI.h</literal> etc).
+</para>
+</sect2>
+