X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=docs%2Fusers_guide%2Fwin32-dlls.xml;h=bf243a2cd1c780eb56a1f39656503e2f84420cb8;hb=d91240674cd45cb4677adca5829a1851ba3cd044;hp=703bb1877dd636a7ef49e8d03a351b06e314068f;hpb=5a99cd502b29503578bc6a227bf80f2db9742e79;p=ghc-hetmet.git
diff --git a/docs/users_guide/win32-dlls.xml b/docs/users_guide/win32-dlls.xml
index 703bb18..bf243a2 100644
--- a/docs/users_guide/win32-dlls.xml
+++ b/docs/users_guide/win32-dlls.xml
@@ -71,7 +71,7 @@ Notice how the "%1" argument is quoted (or not).
This problem doesn't just affect GHCi, it affects any
GHC-compiled program that wants to catch console events. See the
GHC.ConsoleHandler
+ url="&libraryBaseLocation;/GHC-ConsoleHandler.html">GHC.ConsoleHandler
module.
@@ -210,7 +210,8 @@ make-sessions running under cygwin.
Making Haskell libraries into DLLs doesn't work on Windows at the
-moment; we hope to re-instate this facility in the future. Note that
+moment; we hope to re-instate this facility in the future
+(see ). Note that
building an entire Haskell application as a single DLL is still supported: it's
just multi-DLL Haskell programs that don't work. The Windows
distribution of GHC contains static libraries only.
@@ -402,227 +403,152 @@ non-static to static linking is simply a question of adding
Making DLLs to be called from other languages
-If you want to package up Haskell code to be called from other languages,
-such as Visual Basic or C++, there are some extra things it is useful to
-know. This is a special case of ; we'll deal with
- the DLL-specific issues that arise below. Here's an example:
+ This section describes how to create DLLs to be called from other languages,
+ such as Visual Basic or C++. This is a special case of
+ ; we'll deal with the DLL-specific issues that
+ arise below. Here's an example:
-
-
-
-
-Use foreign export declarations to export the Haskell
-functions you want to call from the outside. For example,
-
+ Use foreign export declarations to export the Haskell functions you want to
+ call from the outside. For example:
+
+-- Adder.hs
+{-# LANGUAGE ForeignFunctionInterface #-}
module Adder where
-adder :: Int -> Int -> IO Int –– gratuitous use of IO
+adder :: Int -> Int -> IO Int -- gratuitous use of IO
adder x y = return (x+y)
foreign export stdcall adder :: Int -> Int -> IO Int
-
-
-
-
-Compile it up:
-
-
-ghc -c adder.hs -fglasgow-exts
-
-
-This will produce two files, adder.o and adder_stub.o
+ Add some helper code that starts up and shuts down the Haskell RTS:
-
-
-
-
-compile up a DllMain() that starts up the Haskell
-RTS-––a possible implementation is:
-
-#include <windows.h>
+// StartEnd.c
#include <Rts.h>
extern void __stginit_Adder(void);
-static char* args[] = { "ghcDll", NULL };
- /* N.B. argv arrays must end with NULL */
-BOOL
-STDCALL
-DllMain
- ( HANDLE hModule
- , DWORD reason
- , void* reserved
- )
+void HsStart()
{
- if (reason == DLL_PROCESS_ATTACH) {
- /* By now, the RTS DLL should have been hoisted in, but we need to start it up. */
- startupHaskell(1, args, __stginit_Adder);
- return TRUE;
- }
- return TRUE;
-}
-
+ int argc = 1;
+ char* argv[] = {"ghcDll", NULL}; // argv must end with NULL
-Here, Adder is the name of the root module in the module
-tree (as mentioned above, there must be a single root module, and hence a
-single module tree in the DLL).
-
-Compile this up:
+ // Initialize Haskell runtime
+ char** args = argv;
+ hs_init(&argc, &args);
-
-ghc -c dllMain.c
-
-
-
+ // Tell Haskell about all root modules
+ hs_add_root(__stginit_Adder);
+}
-
+void HsEnd()
+{
+ hs_exit();
+}
+
-Construct the DLL:
-
+ Here, Adder is the name of the root module in the module
+ tree (as mentioned above, there must be a single root module, and hence a
+ single module tree in the DLL). Compile everything up:
+
-ghc –shared -o adder.dll adder.o adder_stub.o dllMain.o
+ghc -c Adder.hs
+ghc -c StartEnd.c
+ghc -shared -o Adder.dll Adder.o Adder_stub.o StartEnd.o
-
-
-
-
-
-Start using adder from VBA-––here's how I would
-Declare it:
-
-
-Private Declare Function adder Lib "adder.dll" Alias "adder@8"
- (ByVal x As Long, ByVal y As Long) As Long
-
-
-Since this Haskell DLL depends on a couple of the DLLs that come with GHC,
-make sure that they are in scope/visible.
+ Now the file Adder.dll can be used from other
+ programming languages. Before calling any functions in Adder it is necessary
+ to call HsStart, and at the very end call
+ HsEnd.
-
-Building statically linked DLLs is the same as in the previous section: it
-suffices to add to the commands used to compile up
-the Haskell source and build the DLL.
+ Warning: It may appear tempting to use
+ DllMain to call
+ hs_init/hs_exit, but this won't work
+ (particularly if you compile with -threaded). There are
+ severe restrictions on which actions can be performed during
+ DllMain, and hs_init violates these
+ restrictions, which can lead to your dll freezing during startup (see
+ bug
+ #3605).
-
-
-
-
-
-
-
-Beware of DllMain()!
-
-The body of a DllMain() 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 DllMain() 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
-DllMain(), unless your shutdown code only requires use of certain
-functions which are guaranteed to be available (see the Platform SDK
-docs for more info).
-
-In particular, if you are writing a DLL that's statically
-linked with Haskell, it is not safe to call
-hs_exit() from DllMain(), since
-hs_exit() may make use of other DLLs (see also ). 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
-DllMain(), which can cause even more
-problems.
-
-A solution is to always export Begin() and End() 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.
-
-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 Bar and Zap,
-where Bar imports Zap and is
-therefore the root module in the sense of . Then the main C++ unit for the DLL would
-look something like:
+
+Using from VBA
+
+ An example of using Adder.dll from VBA is:
+
- // 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;
- }
+Private Declare Function Adder Lib "Adder.dll" Alias "adder@8" _
+ (ByVal x As Long, ByVal y As Long) As Long
- LEWIS_API void lewis_End(){
- hs_exit();
- }
+Private Declare Sub HsStart Lib "Adder.dll" ()
+Private Declare Sub HsEnd Lib "Adder.dll" ()
- LEWIS_API HsInt lewis_Test(HsInt x){
- // use Haskell functions exported by
- // modules Bar and/or Zap
+Private Sub Document_Close()
+HsEnd
+End Sub
- return ...
- }
+Private Sub Document_Open()
+HsStart
+End Sub
- } // extern "C"
+Public Sub Test()
+MsgBox "12 + 5 = " & Adder(12, 5)
+End Sub
+
+
+ This example uses the
+ Document_Open/Close functions of
+ Microsoft Word, but provided HsStart is called before the
+ first function, and HsEnd after the last, then it will
+ work fine.
+
+
-and some application which used the functions in the DLL would have a main() function like:
+
+Using from C++
- // MyApp.cpp
- #include "stdafx.h"
- #include "Lewis.h"
+
+ An example of using Adder.dll from C++ is:
+
- int main(int argc, char *argv[]){
- if (lewis_Begin()){
- // can now safely call other functions
- // exported by Lewis DLL
+
+// Tester.cpp
+#include "HsFFI.h"
+#include "Adder_stub.h"
+#include <stdio.h>
+
+extern "C" {
+ void HsStart();
+ void HsEnd();
+}
- }
- lewis_End();
- return 0;
- }
+int main()
+{
+ HsStart();
+ // can now safely call functions from the DLL
+ printf("12 + 5 = %i\n", adder(12,5)) ;
+ HsEnd();
+ return 0;
+}
-
-Lewis.h would have to have some appropriate #ifndef 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 HsFFI.h etc).
+
+ This can be compiled and run with:
+
+$ ghc -o tester Tester.cpp Adder.dll.a
+$ tester
+12 + 5 = 17
+
+
+
+
@@ -630,7 +556,6 @@ the include files like HsFFI.h etc).