首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何编写调用Win32函数的通用C函数?

如何编写调用Win32函数的通用C函数?
EN

Stack Overflow用户
提问于 2009-03-09 10:50:35
回答 8查看 3.6K关注 0票数 6

为了允许从脚本语言(用C编写)访问Win32 API,我想编写如下函数:

代码语言:javascript
复制
void Call(LPCSTR DllName, LPCSTR FunctionName, 
  LPSTR ReturnValue, USHORT ArgumentCount, LPSTR Arguments[])

它将一般地调用任何Win32 API函数。

( LPSTR参数实际上是作为字节数组使用的--假设它们的大小是正确的,以便在函数外部获得正确的数据类型。另外,我认为区分指针和非指针参数还需要一些额外的复杂性,但为了这个问题,我忽略了这一点)。

我遇到的问题是将参数传递到Win32 API函数中。因为这些都是stdcall,所以我不能使用varargs,所以“调用”的实现必须事先知道参数的数量,因此它不能是泛型的.

我认为我可以通过程序集代码(通过遍历参数,将每个参数推到堆栈)来实现这一点,但是这在纯C中是可能的吗?

更新:,我已经标记了“不,这是不可能的”答案,目前已被接受。如果一个基于C的解决方案被曝光,我当然会改变这一点。

更新: 红宝石/dl看起来可能是使用合适的机制实现的。关于这方面的任何细节将不胜感激。

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2009-03-09 11:09:38

不,我认为不写汇编是不可能的。原因是在调用目标函数之前,需要对堆栈上的内容进行精确控制,在纯C中没有真正的方法可以做到这一点。当然,在汇编中这样做很简单。

而且,对于所有这些参数,您都使用了PCSTR,这实际上就是const char *。但是由于所有这些arg都不是字符串,所以您实际上想要用于返回值和Arguments[]的是void *LPVOID。这是当您不知道参数的真正类型时应该使用的类型,而不是将它们转换为char *

票数 5
EN

Stack Overflow用户

发布于 2009-03-09 11:11:09

首先:在C中不能将类型作为参数传递,剩下的唯一选项是宏。

只要您执行一个LoadLibrary/GetProcAddress来调用Win32函数,这个方案就可以进行一些修改(用于参数的void*数组)。如果没有函数名字符串,那就没用了。在C中,调用函数的唯一方法是通过它的名称(标识符),在大多数情况下,该名称会衰减到指向函数的指针。您还必须处理转换返回值的问题。

我最好的选择是:

代码语言:javascript
复制
// define a function type to be passed on to the next macro
#define Declare(ret, cc, fn_t, ...) typedef ret (cc *fn_t)(__VA_ARGS__)

// for the time being doesn't work with UNICODE turned on
#define Call(dll, fn, fn_t, ...) do {\
    HMODULE lib = LoadLibraryA(dll); \
    if (lib) { \
        fn_t pfn = (fn_t)GetProcAddress(lib, fn); \
        if (pfn) { \
            (pfn)(__VA_ARGS__); \
        } \
        FreeLibrary(lib); \
    } \
    } while(0)

int main() {
    Declare(int, __stdcall, MessageBoxProc, HWND, LPCSTR, LPCSTR, UINT);

    Call("user32.dll", "MessageBoxA", MessageBoxProc, 
          NULL, ((LPCSTR)"?"), ((LPCSTR)"Details"), 
          (MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2));

    return 0;
}
票数 9
EN

Stack Overflow用户

发布于 2009-04-08 06:49:28

其他帖子是正确的,几乎肯定需要组装或其他非标准的技巧来进行调用,更不用说实际调用约定的所有细节了。

Windows至少对函数使用两个不同的调用约定:stdcallcdecl。您需要同时处理这两种情况,甚至可能需要确定使用哪一种。

处理此问题的一种方法是使用现有的库来封装许多细节。令人惊讶的是,有一个:利布菲。在脚本环境中使用它的一个例子是Lua 外星人的实现,它是一个Lua模块,允许在纯Lua中创建任意DLL的接口,而不是外国人本身。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/625784

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档