1 module yu.tools.sharedlib;
2 
3 import yu.string : CStr;
4 import std.traits : isFunctionPointer;
5 import std.experimental.allocator.mallocator : Mallocator;
6 
7 @trusted struct SharedLib
8 {
9 nothrow:
10 @nogc:
11     version(Posix)
12     {
13         import core.sys.posix.dlfcn;
14         alias LibHandle = void *;
15     }
16     else version(Windows)
17     {
18          import core.sys.windows.windows;
19          alias LibHandle = HMODULE;
20     }
21     else 
22         static assert(0, "Unsupported operating system");
23     
24     this(string name){loadLib(name);}
25 
26     ~this(){unloadLib();}
27 
28     @property handle(){return _handle;}
29 
30     @property bool isValid() const { return _handle !is null; }
31 
32     bool loadLib(string name)
33     {
34         unloadLib();
35         if(name.length == 0) 
36             return false;
37         version(Posix){
38             auto str = CStr!Mallocator(name);
39              _handle = dlopen(str.ptr,RTLD_LAZY);
40         } else {
41             import core.stdc.stddef;
42             auto len = MultiByteToWideChar(CP_UTF8, 0, name.ptr, cast(int)name.length, null, 0);
43             if (len == 0) return false;
44             auto buf =  cast(wchar_t[])Mallocator.instance.allocate((len+1) * wchar_t.sizeof);
45             if (buf.ptr is null) return false;
46             scope(exit) Mallocator.instance.deallocate(buf);
47             len = MultiByteToWideChar(CP_UTF8, 0, name.ptr, cast(int)name.length, buf.ptr, len);
48             if (len == 0) return false;
49             buf[len] = '\0';
50             _handle = LoadLibraryW(buf.ptr);
51         }
52         return isValid();
53     }
54 
55     void unloadLib()
56     {
57         if(_handle is null) return;
58         scope(exit) _handle = null; 
59         version(Posix)
60             dlclose(_handle);
61         else 
62             FreeLibrary(_handle);
63     }
64 
65     auto getFunction(T)(string symbol) if(isFunctionPointer!T)
66     {
67         return cast(T)getSymbol(symbol);
68     }
69 
70     void * getSymbol(string symbol)
71     {
72         return dllSymbol(_handle, symbol);
73     }
74 
75     static void * dllSymbol(LibHandle handle, string symbol)
76     {
77         if(handle is null || symbol.length == 0) return null;
78         auto str = CStr!Mallocator(symbol);
79         version (Posix)
80             return dlsym(handle, str.ptr);
81         else
82             return GetProcAddress(handle, str.ptr);
83     }
84 
85 private:
86     @disable this(this);
87     LibHandle _handle = null;
88 }
89 
90 unittest
91 {
92     import std.stdio;
93     import std.string;
94 
95     alias getVersion = char * function() @nogc nothrow;
96     
97     auto lib = SharedLib("libcurl.so");
98 	writeln("is load : ", lib.isValid);
99 	if(lib.isValid){
100 		auto ver = lib.getFunction!getVersion("curl_version");
101 		writeln(fromStringz(ver()));
102 	}
103 }