C# 回调函数在构建和动态链接库时的作用

C# 回调函数在构建和动态链接库时的作用,c#,c++,windows,visual-c++,function-pointers,C#,C++,Windows,Visual C++,Function Pointers,回调函数等同于C#(.NET)中的事件 我对回调函数的理解是,它是一个通过引用该函数来调用的函数 示例代码为: void cbfunc() { printf("called"); } int main () { void (*callback)(void); callback=(void *)cbfunc; callback(); return 0; } 现在我不明白的是,在从DLL向客户机发送通知方面,这是如何充分使用的 假设我想在

回调函数等同于C#(.NET)中的事件

我对回调函数的理解是,它是一个通过引用该函数来调用的函数

示例代码为:

void cbfunc()

{
        printf("called");
 }

int main ()

{

    void (*callback)(void);

    callback=(void *)cbfunc;

   callback();

   return 0;
}

现在我不明白的是,在从DLL向客户机发送通知方面,这是如何充分使用的

假设我想在接收DLL method2()上的数据时执行一些method1()


与.NET中的事件进行任何比较都非常有帮助。

您将指针传递给第三方例程(不必是DLL),当需要通知时,克隆指针会“回调”

它与.net事件类似,后者也是一种回调类型

// Begin library/dll Public Interface used by an executable
class mydll_interface {  
public:  
    typedef void (*callback_func_t)();  
public:  
    virtual void do_something() = 0;  
    virtual void registerFunction( callback_func_t ) = 0;  
};  

static mydll_interface* getMyDllInterface();

// End library/dll Public Interface used by an executable

// Begin library/dll Private implementation
class mydll_implementation : public mydll_interface {  
public:  
    void do_something() {  
        printf("Hello World\n");  
        _callback_func();  
    }  
    void registerFunction( callback_func_t c) {  
        _callback_func = c;  
    }  
private:  
    callback_func_t _callback_func;  
};  

static mydll_interface* getMyDllInterface() {  
    return new mydll_implementation();  
};  
// End library/dll Private implementation

// Begin main executable code
void myMainAppFunc() {  
    printf("hello World Again\n");  
}  

int main() {    
    mydll_interface* iface = getMyDllInterface();  
    iface->registerFunction(&myMainAppFunc);  
    iface->do_something();  
};  
// End main executable code

将指针传递给第三方例程(不必是DLL),当需要通知时,克隆指针将“回调”该指针

它与.net事件类似,后者也是一种回调类型

// Begin library/dll Public Interface used by an executable
class mydll_interface {  
public:  
    typedef void (*callback_func_t)();  
public:  
    virtual void do_something() = 0;  
    virtual void registerFunction( callback_func_t ) = 0;  
};  

static mydll_interface* getMyDllInterface();

// End library/dll Public Interface used by an executable

// Begin library/dll Private implementation
class mydll_implementation : public mydll_interface {  
public:  
    void do_something() {  
        printf("Hello World\n");  
        _callback_func();  
    }  
    void registerFunction( callback_func_t c) {  
        _callback_func = c;  
    }  
private:  
    callback_func_t _callback_func;  
};  

static mydll_interface* getMyDllInterface() {  
    return new mydll_implementation();  
};  
// End library/dll Private implementation

// Begin main executable code
void myMainAppFunc() {  
    printf("hello World Again\n");  
}  

int main() {    
    mydll_interface* iface = getMyDllInterface();  
    iface->registerFunction(&myMainAppFunc);  
    iface->do_something();  
};  
// End main executable code

回调函数实现了与C#中委托类似的目的

例如,Win32 API提供了一个计时服务,可以通过调用SetTimer来访问该服务。SetTimer由系统DLL导出,但其机制与在用户DLL中使用的机制完全相同。在代码中,您可以通过执行以下操作来访问计时器:

void 
CALLBACK
MyTimerCallback(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
// do something
}

...

TIMERPROC fn = &MyTimerCallback;
int delay = 500;  
SetTimer(NULL,0,delay,fn); 
调用SetTimer并传入回调函数,允许操作系统在每次计时器计时时回调函数。当然,这里没有多播功能,特别是在SetTimer的情况下,回调函数必须是C函数或静态类方法。没有与函数关联的类或对象实例

类似的模式也可以在.NET中实现——我确信.NET有自己的计时器范例,但我们可以暂时假设它实现了一个使用TimerDelegate的SetTimer函数

在用户代码中,在对象中,您将MyTimerProc定义为一个具有与委托匹配的签名的函数。然后像这样调用它

TimerDelegate d = new TimerDelegate(myObject.MyTimerProc);
SetTimer(0,0,delay,d);
或者,如果“timers”是一个与TimerDelegate匹配的事件,那么等效的C#代码如下所示:

timers += new TimerDelegate(myObject.MyTimerProc);
注意:我的C#非常生疏,所以不要将这些代码示例作为最佳实践,甚至工作代码的示例:p


当定义自己的回调函数时,总是定义回调函数以获取空缺*“上下文”参数是一个很好的做法,因为这允许C++程序员存储他们的“这个”指针并检索它。
// the first parameter to the callback fn is a void* user supplied context parameter
typedef void (CALLBACK* MyCallbackFn)(void* context, int etc);

// and, the dll export function always takes a function pointer, context parameter pair.
DLL_EXPORT void SomeExportedFn(MyCallbackFn, void* context);

回调函数的作用与C#中的委托类似

例如,Win32 API提供了一个计时服务,可以通过调用SetTimer来访问该服务。SetTimer由系统DLL导出,但其机制与在用户DLL中使用的机制完全相同。在代码中,您可以通过执行以下操作来访问计时器:

void 
CALLBACK
MyTimerCallback(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
// do something
}

...

TIMERPROC fn = &MyTimerCallback;
int delay = 500;  
SetTimer(NULL,0,delay,fn); 
调用SetTimer并传入回调函数,允许操作系统在每次计时器计时时回调函数。当然,这里没有多播功能,特别是在SetTimer的情况下,回调函数必须是C函数或静态类方法。没有与函数关联的类或对象实例

类似的模式也可以在.NET中实现——我确信.NET有自己的计时器范例,但我们可以暂时假设它实现了一个使用TimerDelegate的SetTimer函数

在用户代码中,在对象中,您将MyTimerProc定义为一个具有与委托匹配的签名的函数。然后像这样调用它

TimerDelegate d = new TimerDelegate(myObject.MyTimerProc);
SetTimer(0,0,delay,d);
或者,如果“timers”是一个与TimerDelegate匹配的事件,那么等效的C#代码如下所示:

timers += new TimerDelegate(myObject.MyTimerProc);
注意:我的C#非常生疏,所以不要将这些代码示例作为最佳实践,甚至工作代码的示例:p


当定义自己的回调函数时,总是定义回调函数以获取空缺*“上下文”参数是一个很好的做法,因为这允许C++程序员存储他们的“这个”指针并检索它。
// the first parameter to the callback fn is a void* user supplied context parameter
typedef void (CALLBACK* MyCallbackFn)(void* context, int etc);

// and, the dll export function always takes a function pointer, context parameter pair.
DLL_EXPORT void SomeExportedFn(MyCallbackFn, void* context);

回调和接口类是管理代码边界的好方法。它们有助于在代码中创建正式的边界和/或层,而不是将所有内容集中在一起。在处理大型软件解决方案时,这是必要的

下面是一个如何使用回调和接口类的示例。在library/dll代码中,唯一应该向主可执行文件公开的是myddl_接口类和函数getMyDllInterface()。使用这样的接口类完全隐藏了主可执行文件的实现细节。接口类还允许主可执行文件向其注册稍后将执行的函数(即回调)


回调和接口类是管理代码边界的好方法。它们有助于在代码中创建正式的边界和/或层,而不是将所有内容集中在一起。在处理大型软件解决方案时,这是必要的

下面是一个如何使用回调和接口类的示例。在库/dll代码中,唯一应该向