回调函数:将回调从 C# winform 应用程序传递到引用的 VC++ EXE文件
异步回调函数
视角:我正在将几个 VB6 ActiveX 应用程序升级到 C#.net,它们都使用回调函数相互通信,这些函数注册到引用的 VC++.net 可执行文件中。
我无法在 C# 中复制以下 VB6 功能: VB6 能够将包含方法的实例化类作为回调函数参数传递给 VC++,然后 VC++ 将其注册为异步通信的回调函数。
除了这个问题之外,升级进展顺利:回调函数 ...我已经坚持了两周了。请帮我!!!
我已经弄清楚如何将回调函数作为委托传递,我已经设法使用 C# DynamicInvoke 来使用它,但是我确实需要它在 VC++ 中工作。
错误消息 strong> 我不断从 VC++ invoke
语句中得到“参数数量无效”。
下面我概述了处理异步回调的 VB6 和 VC++ 功能。每个 VB6 ActiveX 组件都将包含单个方法的类作为回调函数传递给 VC++ 可执行文件,后者将回调保存在数组中以供以后使用。由于这是现有代码,因此它可以按预期工作。
以下是正在实例化并用作回调的 VB6 类 Class1
:
请注意:Attribute Notify.VB_UserMemId = 0
VERSION 1.0 CLASS
BEGIN
MultiUse = -1
Persistable = 0
DataBindingBehavior = 0
DataSourceBehavior = 0
MTSTransactionMode = 0
END
Attribute VB_Name = "Class1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = True
Sub Notify(ByVal message As Integer, ByVal data As Variant)
Attribute Notify.VB_UserMemId = 0
MsgBox Str$(message) + " " + data, vbInformation, Form1.Text2
End Sub
上面的代码已被简化以避免混淆。
下面是实例化 VC++ 可执行文件 (VCCallbackHandler
) 的 VB6 代码,并将实例化的 Class1
作为回调参数传递给它。
Dim VCCallbackHandler New VCCallbackHandler.VCCallbackHandler
Dim c1 As New Class1
Private Sub Register_Click()
Dim i as int
i = VCCallbackHandler.Register(c1, "NameOfApplication")
End Sub
VC++ 代码注册了回调(见下文),然后如果由其他事件提示(见下文“BroadCast”),VC++ 可以(异步)利用回调。在这种情况下,VC++ exe 充当多个同时运行的应用程序的中央回调处理程序。每个应用程序都已向 VC++ 回调处理程序注册了其回调,当一个应用程序通过调用另一个事件来提示 VC++ 回调处理程序时,所有回调都会被调用。通过这种方式,回调处理程序允许所有其他应用程序相互通信。
下面是相关的VC++.Net回调代码。
注册回调:
#define MAXREG 20
typedef struct tagRegElement {
char name[20]; // Name of registered application
_Callback *p_Callback; // Callback wrapper class
} REG_ELEMENT;
public:
REG_ELEMENT Registry[MAXREG];
short CBreqDlgAutoProxy::Register(LPDISPATCH callback, LPCTSTR name)
{
for (int i = 0;i<MAXREG;i++){
if(!(theApp.Registry[i].name[0]))
{
RegIndex = i;
strcpy(theApp.Registry[i].name,name);
theApp.Registry[i].p_Callback = new _Callback(callback);
return i;
}
}
return -1;
}
调用回调:
BOOL CBreqDlgAutoProxy::Broadcast(short message, const VARIANT FAR& data)
{
for (int i = 0;i<MAXREG;i++){
if(theApp.Registry[i].name[0] && (i != RegIndex)){
if (!theApp.Registry[i].p_Callback->Notify(message,data,theApp.Registry[i].name))
DeRegister(i);
}
}
return TRUE;
}
BOOL _Callback::Notify(short message, VARIANT data, char* RegisteredName)
{
static BYTE parms[] = VTS_I2 VTS_VARIANT;
InvokeHelper(0x0, DISPATCH_METHOD, VT_EMPTY, NULL, parms, message, &data);
return TRUE;
}
注意。 上述可行。
有两种可能的解决方案:
- C#:如何让 C# 将方法作为参数传递。我想出了如何使用委托来做到这一点,但 VC++ 需要一个方法而不是委托。
- VC++:如何让 VC++ 处理委托而不是方法作为要调用的回调。
我没有成功使用以下任何 c# 代码片段:`
Marshal.GetFunctionPointerForDelegate
GCHandle
KeepAlive
我希望有人遇到了这个问题,并且可以去...SNAP...很容易..使用这个...交叉手指。
Asynchronous Callback Functions
Perspective: I am upgrading several VB6 ActiveX applications to C#.net, which all talk to each other using callback functions which they register with a referenced VC++.net executable.
I cannot replicate the following VB6 functionality in C#:
VB6's ability to pass to VC++, an instantiated class containing a method, as a callback function parameter, which VC++ then registers as callback function for asynchronous communication.
The upgrade has gone very well apart from this one problem: CallBack Functions
... and I have been stuck on it now for two weeks. Please help me!!!
I have figured out how to pass a callback function as a delegate, which I have managed to get working with C# DynamicInvoke, however I really need this to work in VC++.
The error message I keep getting from the VC++ invoke
statement is "Invalid Number of Parameters".
BELOW I have outlined the VB6 and VC++ functionality which handles the asynchronous callbacks. The VB6 ActiveX components are each passing a class containing a single method as a callback function to the VC++ Executable, which saves the callbacks in an array for later use. As this is the existing code, it works as expected.
The following is the VB6 Class Class1
being instantiated and used as a callback:
Please note: Attribute Notify.VB_UserMemId = 0
VERSION 1.0 CLASS
BEGIN
MultiUse = -1
Persistable = 0
DataBindingBehavior = 0
DataSourceBehavior = 0
MTSTransactionMode = 0
END
Attribute VB_Name = "Class1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = True
Sub Notify(ByVal message As Integer, ByVal data As Variant)
Attribute Notify.VB_UserMemId = 0
MsgBox Str$(message) + " " + data, vbInformation, Form1.Text2
End Sub
The above code has been simplified to avoid confusion.
Below is the VB6 code that instantiates the VC++ executable(VCCallbackHandler
), and passes it the instantiated Class1
as the callback parameter
Dim VCCallbackHandler New VCCallbackHandler.VCCallbackHandler
Dim c1 As New Class1
Private Sub Register_Click()
Dim i as int
i = VCCallbackHandler.Register(c1, "NameOfApplication")
End Sub
The VC++ code registers the callbacks (see below), and then later(asynchronously) the VC++ can utilise the callbacks, if prompted by some other event (see below 'BroadCast'). In this case the VC++ exe is acting as a central callback handler for several concurrantly running apps. Each app has registered their callback with the VC++ callback handler, and when one app prompts the VC++ callbackHandler by calling another event, all of the callbacks are invoked. In this way the callback handler is allowing all these other applications to communicate with each other.
Below is the relavant VC++.Net callback code.
Registering the callbacks:
#define MAXREG 20
typedef struct tagRegElement {
char name[20]; // Name of registered application
_Callback *p_Callback; // Callback wrapper class
} REG_ELEMENT;
public:
REG_ELEMENT Registry[MAXREG];
short CBreqDlgAutoProxy::Register(LPDISPATCH callback, LPCTSTR name)
{
for (int i = 0;i<MAXREG;i++){
if(!(theApp.Registry[i].name[0]))
{
RegIndex = i;
strcpy(theApp.Registry[i].name,name);
theApp.Registry[i].p_Callback = new _Callback(callback);
return i;
}
}
return -1;
}
Invoking the callbacks:
BOOL CBreqDlgAutoProxy::Broadcast(short message, const VARIANT FAR& data)
{
for (int i = 0;i<MAXREG;i++){
if(theApp.Registry[i].name[0] && (i != RegIndex)){
if (!theApp.Registry[i].p_Callback->Notify(message,data,theApp.Registry[i].name))
DeRegister(i);
}
}
return TRUE;
}
BOOL _Callback::Notify(short message, VARIANT data, char* RegisteredName)
{
static BYTE parms[] = VTS_I2 VTS_VARIANT;
InvokeHelper(0x0, DISPATCH_METHOD, VT_EMPTY, NULL, parms, message, &data);
return TRUE;
}
NOTE. THE ABOVE WORKS.
There are two possible solutions:
- C#: how to get C# to pass a method as a parameter. I figured out how to do it using a delegate, but the VC++ wants a method not a delegate.
- VC++: How to get VC++ to handle a delegate instead of a method as the callback to invoke.
I have had no success with any of the following c# code snippets: `
Marshal.GetFunctionPointerForDelegate
GCHandle
KeepAlive
I hope someone out there has had this problem, and can go... SNAP... its easy.. use this... Crossed fingers.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我以前做过类似的事情,但我用它来传递变量。
C#:如何让 C# 将方法作为参数传递。我想出了如何使用委托来做到这一点,但 VC++ 需要一个方法而不是委托。
我使用了 C++/CLI,因为 C# 代码(托管)无法直接与 VC++ 代码(非托管)对话。
因此,如果您可以编写一个 CLI/C++ 包装器,那将会有所帮助。
附言。我想知道如何将委托传递给 VC++。如果您可以发布代码那就太好了。
I did something like this sometime back , but I used it for passing variables .
C#: how to get C# to pass a method as a parameter. I figured out how to do it using a delegate, but the VC++ wants a method not a delegate.
I had used C++/CLI as C# code (managed ) cannot talk directly to VC++ code ( unmanaged ).
So if you can write a CLI/C++ wrapper , that would help.
PS. I would like to know how to pass the delegate to VC++. If you can post the code that would be great.