我正在尝试构建一个可以根据用户输入动态调用任何Win32 API函数的应用程序。
我想知道如何在C ++中使用函数RegisterCallback
的行为,因为它看起来非常有用,它可以将地址传递给回调函数。
如何使用C ++中的函数实现相同的行为?
我已经成功实现了一个可以调用任何动态库的函数,但是却停留在这样的动态回调中。
例如,我可以使用我的函数调用> inverse = function (f, lower = -100, upper = 100) {
function (y) uniroot((function (x) f(x) - y), lower = lower, upper = upper)[1]
}
> square_inverse = inverse(function (x) x^2, 0.1, 100)
> square_inverse(4)
[1] 1.999976
API,如下所示:
EnumWindows
提前致谢。
编辑:我会解释更多。
假设我有以下代码:
回调功能:
CallLibFunction(GetProcAddress(LoadLibrary(L"User32.dll"), "EnumWindows"), ParamArray, 2, ExepInfo);
主要功能:
BOOL CALLBACK EnumWindowsProc(__in HWND hWnd, __in LPARAM lParam)
{
return TRUE;
}
以上是任何人都可以使用API函数的常用方法。我希望它像这样被调用:
EnumWindows(EnumWindowsProc, NULL);
然后最终动态调用它:
LONGLONG CallbackAddress = <Some Function to get address>&EnumWindowsProc
ParamArray[1].type = VT_I8;
ParamArray[1].llval = CallbackAddress; // Address of `EnumWindowsProc`.
答案 0 :(得分:1)
首先,您需要声明一个指针类型来保存回调的地址。函数的基本定义在c ++中有点奇怪。还有一个复杂的问题是,在C ++中我们有函数,函数对象和模板类型。
该标准提供了一个基本的函数模板类型:std :: function。这个类型 不是一个函数指针,而是一个可调用的对象。
#include <functional>
要声明特定的函数类型,请将其签名传递给std :: function作为其模板参数。
typedef std::function<int(const char*)> StdFreeFunc;
// you can also define types for member functions, and define
// member function pointers this way
struct A{};
typedef std::function<int A::*(const char*)> StdMemberFunc;
// member callable objects are called with this syntax:
// (obj.*callable)(args); or (obj->*callable)(args);
// the parenthesis are often required to keep the compiler happy
// A callable object:
struct CallMe
{
int xy;
int operator()(const char*) { /*...*/ return xy; }
};
std :: function与函数对象,lambdas和常规函数指针兼容(见下文)。最适合使用C ++的东西。
struct AStruct
{
StdFreeFunc callback_; // we hold a value, not a pointer
void setCallback(StdFreeFunc&& cb) // pass by value, reference, const ref,
{ // move... like any object type
callback_ = cb;
};
int callCallback(const char* str)
{
if (callback_) // callable object has a bool() operator to check if valid !!
return (callback_)(str);
// the parenthesis and is optional, so this is the same:
if (callback_)
return callback_(str):
}
};
// example with callable object:
AStruct as, ar;
as.setCallback(CallMe{42}); // we can pass an object with data
ar.setCallback(CallMe{84}); // to obtain different effects
as.callCallback("prints fourty two");
ar.callCallback("prints eighty four");
C风格的函数指针
在C ++之前,有C.它是如何在C中完成的,它确实编译。 C风格函数指针的缺点是它们与函数对象不兼容。另一方面,它们与C和许多其他语言兼容,如PASCAL,VB等。
例如,将const char *作为参数并返回int的函数类型写为:
typedef int (CallBack)(const char*);
最常见的形式是声明指针,因为这是存储的内容。如:
typedef int (*CallBack)(const char*);
// you can specify extra call specifications
typedef int (__stdcall * CallBack)(const char*); // uses PASCAL calling
// exmample:
struct YourStruct
{
//...
Callback callback_{nullptr}; // this is a pointer initialize to nullptr
//...
void setCallback(Callback cb)
{
// call as ys.setCallback(AFunction)
// or ys.setCallback(&AFunction)
callback_ = cb;
};
int callCallback(const char* str)
{
if (callback_) // always check if valid !!
return (*callback_)(str);
// the parenthesis and the * are optional, so this is the same:
if (callback_)
return callback_(str):
}
};
int UserFunction(const char*) { /*...*/ return 0; }
YourStruct ys;
ys.setCallback(&UserFunction);
ys.callCallback("hello");
答案 1 :(得分:1)
阅读link,以下是关于回调地址的说明:
如果运行脚本的exe是32位,则此参数必须介于0和4294967295之间。如果exe为64位,则此参数可以是64位整数。
因此,您需要将指针地址转换为整数类型。从this answer中汲取灵感,以下代码应该为您提供如何在您的情况下进行转换的提示:
#include <iostream>
#include <cstdint>
bool f() {
return true;
}
int main() {
int iv = *((int*)(&f));
long lv = *((long*)(&f));
long long llv = *((long long*)(&f));
intptr_t ipv = *((intptr_t*)(&f));
std::cout << "int: " << iv << std::endl;
std::cout << "long: " << lv << std::endl;
std::cout << "long long: " << llv << std::endl;
std::cout << "intptr_t: " << ipv << std::endl;
}
对我来说这打印:
int: -443987883
long: 82192552476362837
long long: 82192552476362837
intptr_t: 82192552476362837
请注意,int
小到可以覆盖void*
值。您应该能够使用LONGLONG
正确转换,否则intptr_t
似乎是正确的数据类型。