元编程应用之:编译期 DLL 包装类
|
oldrev
2007-02-24
大家好!我刚加入,感觉这里是唯一的中文D语言论坛,真不容易啊。
发一个我写的元编程例子:
// dll.d
// A simple DLL wrapper
// Author: Oldrev (wstring#AT#gmail.com)
import std.c.windows.windows;
import std.stdio;
import std.traits;
import std.string;
import std.metastrings;
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(Format!("alias S.FunctionType FP_%s;", S.Name));
mixin(Format!("S.FunctionType %s;", 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 (S; Symbols)
{
mixin(Format!("%s = getSymbol!(FP_%s)(S.Name);", S.Name, S.Name));
//mixin(Format!("assert(%s);", S.Name));
}
}
private void load()
{
m_handle = LoadLibraryA(toStringz(Path));
assert(m_handle);
}
private void free()
{
FreeLibrary(m_handle);
}
private T getSymbol(T)(char[] sym)
{
return cast(T)getSymbolAddress(sym);
}
private void* getSymbolAddress(char[] sym)
{
assert(m_handle);
return GetProcAddress(m_handle, toStringz(sym));
}
}
void main()
{
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);
}
|
|
|
oldrev
2007-02-25
一个D语言Variant类,演示了 mixin 的强大功能,据火星上的人说比 C++ Boost.variant 紧凑80倍。
D 代码
import std.stdio;
import std.metastrings;
import std.typetuple;
private template MixinMembers(int I, T, V...)
{
mixin(Format!("T var%s;", I));
static if(V.length > 0)
mixin MixinMembers!(I + 1, V);
}
//catenate strings at compile time....
private template MixinThisFunc(char[] S, T, V...)
{
public const char[] Result = S ~
Format!("public this(%s v) { assign!(%s)(v); } ", T.stringof, T.stringof);
pragma(msg, Result ~ "\n");
static if(V.length > 0)
mixin MixinThisFunc!(Result, V);
}
class Variant(TList...)
{
public alias TList TypeList;
public alias Variant!(TList) SelfType;
// no union.tupleof?
private union Holder
{
mixin MixinMembers!(0, TList);
}
private Holder m_holder;
private int m_which = -1;
public mixin(MixinThisFunc!("",TypeList).Result);
public this()
{
m_holder.var0 = m_holder.var0.init;
m_which = 0;
}
public SelfType assign(T)(T rhs)
{
enum { index = IndexOf!(T, TypeList) }
static assert( index >= 0);
mixin(Format!("m_holder.var%s = rhs;", index));
m_which = index;
return this;
}
public SelfType opAssign(T)(T rhs)
{
return assign(rhs);
}
public int which()
{
return m_which;
}
public T get(T)()
{
enum { index = IndexOf!(T, TypeList) }
static assert(index >= 0);
assert(index == which());
mixin(Format!("return m_holder.var%s;", index));
}
}
void main()
{
scope auto v = new Variant!(int, double, char, char[])(1000);
writefln("which: %d", v.which());
v = 100.0;
v = 'A';
writefln("which: %d", v.which());
char[] str = "foobar";
v = str;
writefln("which: %d", v.which());
str = "";
str = v.get!(char[]);
writefln(str);
}
|
|
|
ideage
2007-02-25
太好了,正在学习!
|
|
|
oldrev
2007-02-26
上面那个Variant类好像不支持非POD类型,我重写了一个支持 POD 的,几乎达到了 boost.variant 的功能。
import std.metastrings;
import std.stdio;
import std.typetuple;
import std.traits;
private template MaxSizeImp(T, V...)
{
static if(V.length > 0)
private const int tailResult = MaxSizeImp!(V).result;
else
private const int tailResult = T.sizeof;
public const int result = T.sizeof > tailResult ? T.sizeof : tailResult;
};
template MaxSize(TList...)
{
const int MaxSize = MaxSizeImp!(TList).result;
}
struct Variant(TList...)
{
public alias TList TypeList;
public alias Variant!(TypeList) SelfType;
private alias ubyte[MaxSize!(TypeList)] Holder;
private Holder m_held;
private int m_which = -1;
public int which()
{
return m_which;
}
public SelfType assign(ValueType)(ValueType val)
{
static if(is(ValueType == SelfType))
{
foreach(T; TypeList)
{
const int i = IndexOf!(T, TypeList);
if(val.which == i)
{
assign!(T)(val.get!(T));
m_which = i;
}
}
}
else
{
const int i = IndexOf!(ValueType, TypeList);
static assert(i >= 0);
ValueType* heldPtr = cast(ValueType*)m_held.ptr;
*heldPtr = val;
m_which = i;
}
return *this;
}
public SelfType opAssign(ValueType)(ValueType rhs)
{
return assign!(ValueType)(rhs);
}
public bool opEquals(ValueType)(ValueType rhs)
{
static if(is(ValueType == SelfType))
{
foreach(T; TypeList)
{
const int i = IndexOf!(T, TypeList);
if(i == which)
{
return (rhs.which == which) && (get!(T) == rhs.get!(T));
}
}
}
else
{
const int i = IndexOf!(ValueType, TypeList);
static assert(i >= 0);
ValueType* heldPtr = cast(ValueType*)m_held.ptr;
return *heldPtr == rhs;
}
}
public int opCmp(ValueType)(ValueType rhs)
{
if(rhs == *this)return 0;
static if(is(ValueType == SelfType))
{
foreach(T; TypeList)
{
const int i = IndexOf!(T, TypeList);
if((i == which) && (rhs.which == which))
{
return get!(T) < rhs.get!(T) ? -1 : 1;
}
}
}
else
{
const int i = IndexOf!(ValueType, TypeList);
static assert(i >= 0);
ValueType* heldPtr = cast(ValueType*)m_held.ptr;
return *heldPtr < rhs ? -1 : 1;
}
}
public TypeInfo type()
{
foreach(T; TypeList)
{
const int i = IndexOf!(T, TypeList);
if(i == which)
{
return typeid(TypeList[i]);
}
}
}
public ValueType get(ValueType)()
{
return *(cast(ValueType*)m_held.ptr);
}
public bool empty()
{
return m_which < 0;
}
public bool isKindOf(ValueType)(ValueType val)
{
const int i = IndexOf!(ValueType, TypeList);
static assert(i >= 0);
return which == i;
}
}
void main()
{
class Foo
{
public:
int n = 0;
int x = 0;
int y = 0;
int z = 0;
Foo opAssign(int rhs)
{
z = rhs;
return this;
}
}
Variant!(double, char, int, char[], Foo) v;
v = 2;
assert(v == 2);
v = 2.22;
assert(v == 2.22);
assert(v.type == typeid(double));
v = new Foo;
assert(v.type == typeid(Foo));
v.get!(Foo)() = 2;
assert(v.get!(Foo)().z == 2);
typeof(v) v2 = v;
assert(v2 == v);
assert(v <= 2);
v = cast(char[])"Foobar";
assert(v == cast(char[])"Foobar");
}
|
|
|
qiezi
2007-02-28
写个linux版嘛,用version(Windows)和version(linux)区分开。
下面这个Variant和库里的boxer好像功能相似吧? |
|
|
oldrev
2007-03-01
怎么我老是得到:超人,您的请求服务器暂时无法响应,请体谅人类服务器脆弱的心脏吧。
请稍后再尝试。 |
|
|
oldrev
2007-03-01
> 写个linux版嘛,用version(Windows)和version(linux)区分开。
其实差不多嘛,就是自己换一下dlopen 那些函数。这个类不好用,因为我发现当定义较多函数时会产生超长标识符,导致编译错误 > 下面这个Variant和库里的boxer好像功能相似吧? 与boxer相似的应该是 boost.any variant 是基于栈的可识别联合,你可以仔细看看 boost.any 和 boost.variant 的区别: http://www.boost.org/doc/html/variant/misc.html#variant.versus-any |
|
|
liuwangxia
2008-01-15
oldrev 写道 大家好!我刚加入,感觉这里是唯一的中文D语言论坛,真不容易啊。
发一个我写的元编程例子:
auto dll = new Module!("User32.dll",
Symbol!("MessageBoxW", int function(HWND, LPCWSTR, LPCWSTR, UINT)),
Symbol!("MessageBoxA", int function(HWND, LPCSTR, LPCSTR, UINT))
);
我用 DMD 2.009 编译时上面的句子报错: 引用 template instance Symbol!("MessageBoxW",int function(HANDLE, const wchar*, const wchar*, uint)*) does not match any template declaration
|
|
|
liuwangxia
2008-01-15
oldrev 写道
用 DMD 2.009 编译出错,但没有提供行号: 引用 semicolon expected, not '%'
Declaration expected, not '%' Declaration expected, not '0' |
|
|
liuwangxia
2008-01-15
oldrev 写道 上面那个Variant类好像不支持非POD类型,我重写了一个支持 POD 的,几乎达到了 boost.variant 的功能。
assert(v <= 2); 用 DMD 2.009 编译成功,运行时上句断言出错。 |

