Thread overview
A Simple DLL Wrapper
Feb 22, 2007
oldrev
Feb 23, 2007
David L. Davis
Feb 23, 2007
Bill Baxter
Feb 23, 2007
oldrev
Feb 23, 2007
kris
Feb 23, 2007
Wei Li
Feb 23, 2007
Kristian Kilpi
Feb 23, 2007
torhu
February 22, 2007
I wrote a DLL wrapper template, but why it cannot work fine?


import std.c.windows.windows;
import std.stdio;
import std.traits;
import std.string;
import std.utf;

struct Symbol(char[] SymName, Ret, Params...)
{
    alias Params        Parameters;
    alias Ret           ReturnValue;
    const char[] Name = SymName;
    alias extern(Windows) ReturnValue function (Params) FunctionType;
}

private template SymbolToTypeString(S)
{
    const char[] SymbolToTypeString = S.ReturnValue.stringof ~ "
function" ~
        S.Parameters.stringof;
}

// FP_Function
private template MixinMember(S) //S = Symbol template
{
    //mixin("public alias extern(C) " ~ SymbolToTypeString!(S) ~ " FP_"
~ S.Name ~ ";");
    //mixin("public FP_" ~ S.Name ~ " " ~ S.Name ~ " = null;");
    mixin("public alias S.FunctionType FP_" ~ S.Name ~ ";");
    mixin("public S.FunctionType " ~ S.Name ~ ";");
}


private template MixinAllMembers(S, V...)
{
    mixin MixinMember!(S);
    static if(V.length > 0)
    {
        mixin MixinAllMembers!(V);
    }
}


class Module(char[] Path, Symbols...)
{
    private HMODULE m_handle = null;

    public mixin MixinAllMembers!(Symbols);

    public this()
    {
        load(Path);
        initMembers();
    }

    public ~this()
    {
        free();
    }

    private void initMembers()
    {
        foreach (i, S; Symbols)
        {
            mixin(S.Name ~ " = getSymbol!(FP_" ~ S.Name ~ ")(S.Name);");
        }
    }

    void load(char[] path)
    {

//       m_handle = LoadLibraryW(toUtf16z(path));
        m_handle = LoadLibraryA(toStringz(path));
        assert(m_handle);
    }

    void free()
    {
        if(m_handle != null)
        {
            FreeLibrary(m_handle);
            m_handle = null;
        }
    }

    public T getSymbol(T)(char[] sym)
    {
        return cast(T)getSymbol1(sym);
    }

    public void* getSymbol1(char[] sym)
    {
        return GetProcAddress(m_handle, toStringz(sym));
    }

}


void main()
{
//    int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT
uType);
//    HWND GetDesktopWindow();

    auto dll = new Module!("User32.dll",
            Symbol!("MessageBoxW", int, HWND, LPCWSTR, LPCWSTR, UINT),
            Symbol!("GetDesktopWindow", HWND));
    dll.MessageBoxW(null, toUTF16z("Hello! DLL!"), null, MB_OKCANCEL);
    //dll.MessageBoxW(null, toUTF16z("Hello! DLL!"), toUTF16z("fdsfas"),
MB_OKCANCEL);
    HWND h = dll.GetDesktopWindow();
    writefln(h);

}
February 23, 2007
You're example template/mixin complies and runs fine with dmd v1.007 under WinXP SP2...I see the Messagebox message and the handle ID number in the console area for the main windows' desktop. Tis pretty Kool what you've done! Good work. :)

So what's problem you're seeing?

David L.

-------------------------------------------------------------------
"Dare to reach for the Stars...Dare to Dream, Build, and Achieve!"
-------------------------------------------------------------------
MKoD: http://spottedtiger.tripod.com/D_Language/D_Main_XP.html


February 23, 2007
David L. Davis wrote:
> You're example template/mixin complies and runs fine with dmd v1.007 under WinXP SP2...I see the Messagebox message and the handle ID number in the console area for the main windows' desktop. Tis pretty Kool what you've done! Good work. :)
> 
> So what's problem you're seeing?

That is pretty cool!

It almost works!

It seems only the first two parameters are actually passed correctly -- which makes me thing that maybe the extern(Windows) is getting ignored or handled incorrectly somehow.
Could this be related?
   http://d.puremagic.com/issues/show_bug.cgi?id=962

Actually you can remove the extern(Windows) completely from your code and you get the same result.   So it probably is getting ignored.

--bb
February 23, 2007
The better version:

import std.c.windows.windows;
import std.stdio;
import std.traits;
import std.string;
import std.utf;

struct Symbol(char[] SymName, Ret, Params...)
{
    alias Params        Parameters;
    alias Ret           ReturnValue;
    const char[] Name = SymName;
    extern(Windows) alias ReturnValue function(Params) FunctionType;
}

// FP_Function
private template MixinMember(S) //S = Symbol template
{
    mixin("public alias S.FunctionType FP_" ~ S.Name ~ ";");
    mixin("public S.FunctionType " ~ S.Name ~ ";");
}


private template MixinAllMembers(S, V...)
{
    mixin MixinMember!(S);
    static if(V.length > 0)
    {
        mixin MixinAllMembers!(V);
    }
}


final class Module(char[] Path, Symbols...)
{
    private HMODULE m_handle = null;

    public mixin MixinAllMembers!(Symbols);

    public this()
    {
        load(Path);
        initMembers();
    }

    public ~this()
    {
        free();
    }

    private void initMembers()
    {
        foreach (i, S; Symbols)
        {
            mixin(S.Name ~ " = getSymbol!(FP_" ~ S.Name ~ ")(S.Name);");
        }
    }

    void load(char[] path)
    {

//       m_handle = LoadLibraryW(toUtf16z(path));
        m_handle = LoadLibraryA(toStringz(path));
        assert(m_handle);
    }

    void free()
    {
        if(m_handle != null)
        {
            FreeLibrary(m_handle);
            m_handle = null;
        }
    }

    public T getSymbol(T)(char[] sym)
    {
        return cast(T)getSymbol1(sym);
    }

    public void* getSymbol1(char[] sym)
    {
        return GetProcAddress(m_handle, toStringz(sym));
    }

}


void main()
{

    auto dll = new Module!("User32.dll",
            Symbol!("MessageBoxW", int, HWND, LPCWSTR, LPCWSTR, UINT),
            Symbol!("MessageBoxA", int, HWND, LPCSTR, LPCSTR, UINT)
            );

    dll.MessageBoxW(null, "Hello! DLL! W", "Title W", MB_OK);
    dll.MessageBoxA(null, "Hello! DLL! A", "Title A", MB_OK);

}




February 23, 2007
oldrev wrote:
> The better version:
> 
> import std.c.windows.windows;
> import std.stdio;
> import std.traits;
> import std.string;
> import std.utf;
> 
> struct Symbol(char[] SymName, Ret, Params...)
> {
>     alias Params        Parameters;
>     alias Ret           ReturnValue;
>     const char[] Name = SymName;
>     extern(Windows) alias ReturnValue function(Params) FunctionType;
> }
> 
> // FP_Function
> private template MixinMember(S) //S = Symbol template
> {
>     mixin("public alias S.FunctionType FP_" ~ S.Name ~ ";");
>     mixin("public S.FunctionType " ~ S.Name ~ ";");
> }
> 
> 
> private template MixinAllMembers(S, V...)
> {
>     mixin MixinMember!(S);
>     static if(V.length > 0)
>     {
>         mixin MixinAllMembers!(V);
>     }
> }
> 
> 
> final class Module(char[] Path, Symbols...)
> {
>     private HMODULE m_handle = null;
> 
>     public mixin MixinAllMembers!(Symbols);
> 
>     public this()
>     {
>         load(Path);
>         initMembers();
>     }
> 
>     public ~this()
>     {
>         free();
>     }
> 
>     private void initMembers()
>     {
>         foreach (i, S; Symbols)
>         {
>             mixin(S.Name ~ " = getSymbol!(FP_" ~ S.Name ~ ")(S.Name);");
>         }
>     }
> 
>     void load(char[] path)
>     {
>         //       m_handle = LoadLibraryW(toUtf16z(path));
>         m_handle = LoadLibraryA(toStringz(path));
>         assert(m_handle);
>     }
> 
>     void free()
>     {
>         if(m_handle != null)
>         {
>             FreeLibrary(m_handle);
>             m_handle = null;
>         }
>     }
> 
>     public T getSymbol(T)(char[] sym)
>     {
>         return cast(T)getSymbol1(sym);
>     }
> 
>     public void* getSymbol1(char[] sym)
>     {
>         return GetProcAddress(m_handle, toStringz(sym));
>     }
> 
> }
> 
> 
> void main()
> {
>         auto dll = new Module!("User32.dll",             Symbol!("MessageBoxW", int, HWND, LPCWSTR, LPCWSTR, UINT),             Symbol!("MessageBoxA", int, HWND, LPCSTR, LPCSTR, UINT)             ); 
> 
>     dll.MessageBoxW(null, "Hello! DLL! W", "Title W", MB_OK);
>     dll.MessageBoxA(null, "Hello! DLL! A", "Title A", MB_OK);
> 
> }
> 
> 


That is really, really slick ... would you be willing to donate this to the Tango library?

- Kris
February 23, 2007
kris Wrote:

> oldrev wrote:
> > The better version:
> > 
> > import std.c.windows.windows;
> > import std.stdio;
> > import std.traits;
> > import std.string;
>> ......
> That is really, really slick ... would you be willing to donate this to the Tango library?
> 
> - Kris

Of course, this is my honor. Use it freely.

The final version:
// dll.d
// A simple DLL wrapper
// Author: Wei Li (wstring@gmail.com)


import std.c.windows.windows;
import std.stdio;
import std.traits;
import std.string;

struct Symbol(char[] Sym, Func)
{
    const char[] Name = Sym;
    extern(Windows) alias ReturnType!(Func)
        function(ParameterTypeTuple!(Func))     FunctionType;

    // extern(Windows) alias FuncType   FunctionType // Why is this Invalid? DMD's bug?
}

private template MixinMembers(S, V...)
{
    mixin("alias S.FunctionType FP_" ~ S.Name ~ ";");
    mixin("S.FunctionType " ~ S.Name ~ ";");

    static if(V.length > 0)
        mixin MixinMembers!(V);
}


final class Module(char[] Path, Symbols...)
{
    private HMODULE m_handle = null;

    public mixin MixinMembers!(Symbols);

    public this()
    {
        load();
        initSymbols();
    }

    public ~this()
    {
        free();
    }

    private void initSymbols()
    {
        foreach (i, S; Symbols)
        {
            mixin(S.Name ~ " = getSymbol!(FP_" ~ S.Name ~ ")(S.Name);");
        }
    }


    private void load()
    {
        m_handle = LoadLibraryA(toStringz(Path));
        assert(m_handle);
    }

    private void free()
    {
        FreeLibrary(m_handle);
    }

    public T getSymbol(T)(char[] sym)
    {
        return cast(T)getSymbolAddress(sym);
    }

    public void* getSymbolAddress(char[] sym)
    {
        return GetProcAddress(m_handle, toStringz(sym));
    }
}


void main()
{

    scope auto dll = new Module!("User32.dll",
            Symbol!("MessageBoxW", int function(HWND, LPCWSTR, LPCWSTR, UINT)),
            Symbol!("MessageBoxA", int function(HWND, LPCSTR, LPCSTR, UINT))
            );

    dll.MessageBoxW(null, "Hello! DLL! ", "Hello from MessageBoxW", MB_OK);
    dll.MessageBoxA(null, "Hello! DLL! ", "Hello from MessageBoxA", MB_OK);

}

                                                                          - Wei Li


February 23, 2007
On Fri, 23 Feb 2007 08:39:57 +0200, oldrev <wstring@gmail.com> wrote:
> The better version:
>
> import std.c.windows.windows;
> import std.stdio;
> import std.traits;
> import std.string;
> import std.utf;
>
> struct Symbol(char[] SymName, Ret, Params...)
> {
>     alias Params        Parameters;
>     alias Ret           ReturnValue;
>     const char[] Name = SymName;
>     extern(Windows) alias ReturnValue function(Params) FunctionType;
> }
>
> // FP_Function
> private template MixinMember(S) //S = Symbol template
> {
>     mixin("public alias S.FunctionType FP_" ~ S.Name ~ ";");
>     mixin("public S.FunctionType " ~ S.Name ~ ";");
> }
>
>
> private template MixinAllMembers(S, V...)
> {
>     mixin MixinMember!(S);
>     static if(V.length > 0)
>     {
>         mixin MixinAllMembers!(V);
>     }
> }
>
>
> final class Module(char[] Path, Symbols...)
> {
>     private HMODULE m_handle = null;
>
>     public mixin MixinAllMembers!(Symbols);
>
>     public this()
>     {
>         load(Path);
>         initMembers();
>     }
>
>     public ~this()
>     {
>         free();
>     }
>
>     private void initMembers()
>     {
>         foreach (i, S; Symbols)
>         {
>             mixin(S.Name ~ " = getSymbol!(FP_" ~ S.Name ~ ")(S.Name);");
>         }
>     }
>
>     void load(char[] path)
>     {
> //       m_handle = LoadLibraryW(toUtf16z(path));
>         m_handle = LoadLibraryA(toStringz(path));
>         assert(m_handle);
>     }
>
>     void free()
>     {
>         if(m_handle != null)
>         {
>             FreeLibrary(m_handle);
>             m_handle = null;
>         }
>     }
>
>     public T getSymbol(T)(char[] sym)
>     {
>         return cast(T)getSymbol1(sym);
>     }
>
>     public void* getSymbol1(char[] sym)
>     {
>         return GetProcAddress(m_handle, toStringz(sym));
>     }
>
> }
>
>
> void main()
> {
>    auto dll = new Module!("User32.dll",
>             Symbol!("MessageBoxW", int, HWND, LPCWSTR, LPCWSTR, UINT),
>             Symbol!("MessageBoxA", int, HWND, LPCSTR, LPCSTR, UINT)
>             );
>
>     dll.MessageBoxW(null, "Hello! DLL! W", "Title W", MB_OK);
>     dll.MessageBoxA(null, "Hello! DLL! A", "Title A", MB_OK);
>
> }
>
>

Very nice indeed! :)
February 23, 2007
oldrev wrote:
<snip>
> 
> void main()
> {
>         auto dll = new Module!("User32.dll",             Symbol!("MessageBoxW", int, HWND, LPCWSTR, LPCWSTR, UINT),             Symbol!("MessageBoxA", int, HWND, LPCSTR, LPCSTR, UINT)             ); 
> 
>     dll.MessageBoxW(null, "Hello! DLL! W", "Title W", MB_OK);
>     dll.MessageBoxA(null, "Hello! DLL! A", "Title A", MB_OK);
> 
> }


Pretty cool.  Reminds me abit of the python module called ctypes. Here's the equivalent of your main() using that:

from ctypes import windll
MB_OK = 0
windll.user32.MessageBoxA(None, "Hello! DLL! ", "Hello from MessageBoxA", MB_OK)
windll.user32.MessageBoxW(None, u"Hello! DLL! ", u"Hello from MessageBoxW", MB_OK)


windll is an object that loads a dll file, and expects functions to use the stdcall conventions.  cdll excpects regular C calling conventions.

Arguments are converted correctly according to their types, only works for ansi and utf8 string, and ints for now.  You have to specify other types explicitly.  Functions are assumed to return int unless otherwise specified.

You can do pointless stuff like this too:
cdll.msvcrt.strlen("123") # returns 3

http://python.net/crew/theller/ctypes/tutorial.html  (use google cache if down)
http://docs.python.org/lib/module-ctypes.html