D 如何轻松地初始化函数指针?

D 如何轻松地初始化函数指针?,d,dmd,D,Dmd,我想使用Runtime.loadLibrary和GetProcAddress(…)加载Win32 API函数。使用mixin: template GetProcA(alias func, alias name_in_DLL) { const char[] GetProcA = func ~ ` = cast(typeof(`~func~`)) GetProcAddress(hModule,"`~name_in_DLL~`");`; } ... static extern (Windows

我想使用
Runtime.loadLibrary
GetProcAddress(…)
加载Win32 API函数。使用
mixin

template GetProcA(alias func, alias name_in_DLL)
{
    const char[] GetProcA = func ~ ` = cast(typeof(`~func~`)) GetProcAddress(hModule,"`~name_in_DLL~`");`;
}
...
static extern (Windows) Object function (HWND hWnd, int nIndex) GetWindowLong;
static extern (Windows) Object function (HWND hWnd, int nIndex, Object dwNewLong) SetWindowLong;
我可以这样实例化它(在类构造函数中):

mixin GetProcA!("SetWindowLong", "SetWindowLongA");
但如果再次将其用于其他功能:

mixin GetProcA!("GetWindowLong", "GetWindowLongA");
编译器抱怨:

mixin GetProcA!("GetWindowLong","GetWindowLongA") GetProcA isn't a template...

我看不出有什么意义:如果第一个实例化创建了
GetProcA
,我不能再次使用它,那么它在这里对我有什么帮助呢?

从您的代码判断,您想要的是一个,而不是:

事实上,你甚至不需要混音。一个内部模板函数就足够了:

hModule = ...;

void GetProcA(T)(ref T func, string name_in_all)
{
    func = cast(typeof(func)) GetProcAddress(hModule, toStringz(name_in_all));
}

GetProcA(SetWindowLong, "SetWindowLongA");
GetProcA(GetWindowLong, "GetWindowLongA");

我认为这是正确的。但是,为了完整性,如果命名相同的模板,则可以多次使用它们。搜索。

两项工作-谢谢!但使用模板不会增加我的可执行文件大小吗?对于每个签名稍有不同的函数(
int
而不是作为输入变量的
uint
),会生成更多的代码(并且几乎相同),不是吗?确实,您会得到代码膨胀,但它应该很小。生成的函数只是转发参数和另一个函数的返回值。在机器代码级别,实际强制转换应为无操作。事实上,智能编译器可能能够将函数的所有实例折叠在一起。此外,无论字符串mixin选项的签名有多少,每次使用都会导致膨胀。@KennyTM:这难道不应该有一个模板约束将其限制为函数指针吗?@BCS:我担心的是整个函数代码都会重复。概括函数类型是一个问题:在一个函数中传递一个
字节
,在另一个函数中传递一个
int
(32/64位),这只是一个变量条目——在两个变量上会加倍,依此类推。。。正确-每个表达式都会“膨胀”代码,但当我导入整个
User32.dll
时,我只希望有N个函数指针-我不想添加到额外的N个函数指针加载器中。@Tal,Kenny建议的模板将针对您使用它的每个签名进行实例化。如果您加载了100个函数,但它们只有3个签名,那么它将只实例化3次。此外,我预计每个实例化最多会有十几个操作代码,所以这只是一个小问题。整个
mixin
/
template
/
template mixin
的东西让我很困惑。。
mixin
结果是否以某种方式嵌入到代码中?当执行第一条CPU指令时,
mixin
的结果已经在二进制文件中“硬编码”:字符串mixin会使被混合的表达式(在编译时)被计算,结果字符串被注入到代码中,编译器会处理它(有点像C
#define
)。模板mixin实例化模板并将其声明移植到范围中。-对于这两种情况,如果生成的代码具有运行时依赖项(例如调用
GetProcAddress
),则无法在编译时计算生成的D代码。如果OTOH,生成的代码没有这样的依赖关系,编译器可能会进行常量折叠。因此我的理解是,编译器会尽最大努力在编译期间将其植入硬编码,但如果不能,则会在运行时执行
mixin
。对吗?@Tal。啊,不。字符串表达式将在编译时进行计算(如果不能,您将得到一个错误),其结果将作为代码的一部分进行处理。在这一点上(仍在编译过程中),它只是另一段代码,编译器可能能够像任何其他代码位一样对其进行部分计算(通过常数折叠)在源文件中,任何字符串mixin都可以替换为它所混合的表达式的文本,结果将与原始代码相同(除了行号)。
hModule = ...;

void GetProcA(T)(ref T func, string name_in_all)
{
    func = cast(typeof(func)) GetProcAddress(hModule, toStringz(name_in_all));
}

GetProcA(SetWindowLong, "SetWindowLongA");
GetProcA(GetWindowLong, "GetWindowLongA");