从VB向DLL中的外部C函数传递指针 我是一个C++(MSVC)编写者,VB新手,试图帮助一个专家,以前从未做过这个任务。p> 我们希望开发C/C++和VB应用程序,使用C++编写的带有C外部API函数的DLL。C++程序运行正常。这是我们遇到困难的地方
DLL提供一个从VB向DLL中的外部C函数传递指针 我是一个C++(MSVC)编写者,VB新手,试图帮助一个专家,以前从未做过这个任务。p> 我们希望开发C/C++和VB应用程序,使用C++编写的带有C外部API函数的DLL。C++程序运行正常。这是我们遇到困难的地方,c++,vb.net,dll,C++,Vb.net,Dll,DLL提供一个外部C函数: RegisterCallback( void* cbFuncPtr, void* dataPtr ); 注1:有关设计变更以及我们做出变更的原因,请参见下面我的说明。 注2:下面添加了其他更新作为答案。 其中回调函数具有以下C类型定义: typedef (void)(* CALL_NACK)(void*); cbFuncPtr应该是指向某个VB函数的函数指针,该函数将作为回调函数被调用。dataPtr是指向具有此C定义的数据结构的指针: typedef str
外部C
函数:
RegisterCallback( void* cbFuncPtr, void* dataPtr );
注1:有关设计变更以及我们做出变更的原因,请参见下面我的说明。
注2:下面添加了其他更新作为答案。
其中回调函数具有以下C类型定义:
typedef (void)(* CALL_NACK)(void*);
cbFuncPtr
应该是指向某个VB函数的函数指针,该函数将作为回调函数被调用。dataPtr
是指向具有此C定义的数据结构的指针:
typedef struct
{
int retCode;
void* a_C_ptr;
char message[500];
} cbResponse_t;
其中,a_C_ptr是DLL中的一个内部指针,VB可以将其转换为
long`。它唯一地标识了在DLL中进行回调的位置,并允许VB函数识别来自相同/不同位置的调用
我们可以从VB中访问并运行RegisterCallback()
函数。日志记录显示我们到达了那里,数据被传入。问题似乎在于实际数据
在阅读了大约一百万个论坛条目后,我们了解到VB不知道指针是什么,VB结构不仅仅是有组织的内存。我们非常确定VB结构的“地址”不是C所认为的地址。我们已经看到了对“封送”和“托管数据”的重复引用,但缺乏足够的理解,无法了解它们告诉了我们什么
<>我们应该如何编码VB来给DLL它的回调函数的执行地址,以及我们如何编码一个VB结构,DLL可以像C++那样?
我们是否需要一个DLL函数,调用应用程序可以说“C”或“VB”,并让DLL以不同的方式处理结构指针?如果是这样的话,如何编写C来填充VB结构?这太大太深了,不能仅仅是对原始帖子的编辑 从@DaveNewman发布的文章中,我提取了以下宝石:
这里有一点关于紧凑型框架,但在 成年人框架: NET Compact Framework支持结构的自动封送 以及包含简单类型的类。所有的场地都布置好了 在内存中按它们在 结构或类定义。类和结构都出现在 本机代码作为指向C/C++结构的指针 托管堆中的对象可以随时在内存中移动 通过垃圾收集器,因此它们的物理地址可能会更改 没有通知。P/Invoke自动固定托管对象 在每个方法调用的持续时间内按引用传递。这意味着 传递给非托管代码的指针将对该调用有效。 请记住,不能保证对象不会被删除 在后续调用中移动到其他内存地址
这是
寄存器回调(fcnPtr、dataPtr)
功能的主要障碍。在注册时传入的指针可以随时更改RegisterCallback()
不是当前语句。发帖作者这样总结
您不需要做任何事情,因为在调用期间结构会自动固定
当然,这意味着在电话之外没有被压制住
出于这个原因,我们决定对设计进行更改,使响应结构内置在DLL的C/C++世界中,而不是在VB的空间中。这样它就不会动了。实际回调函数的签名将保持不变,因此VB程序可以知道DLL将响应放在哪里。这也允许DLL中的响应者为不同的需求分配不同的响应结构。再一次,我的更新太大,不能只发表评论 2013年4月18日更新: 那么,试图使用上面引用的代码是失败的。最后,我们不得不向DLL添加/clr,以便将DLL转换为托管代码,这使得它无法从C应用程序中使用
我们现在测试这个例子,在这个例子中我可以展示一个用VB和C++来工作的DLL。你需要有足够的时间来完成这项工作
这里是C++(C真)测试仪的代码。作为MSVC项目编译
注意:请注意这一行中的_cdecl:
typedef bool (__cdecl *FPtr)(BOOL_FP_INT fp, int i );
这是我必须找到的秘密。DLL和此应用程序使用uu cdecl链接编译,而不是u stdcall。它们是VC++中的默认值,我只是使用了默认值。我试着把所有东西都改成stdcall,但没用。必须是cdecl
//pinvoketest.cpp:定义控制台应用程序的入口点。
//
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义PINVOKELIB_API____declspec(dllimport)
HINSTANCE hLib;//Windows DLL句柄
bool回调VBCallBack(int值);
布尔附属图书馆(作废);
void*GetFuncAddress(HINSTANCE hLib,const char*procname);
int main(int argc,char*argv[])
{
如果(!AttachLibrary())
{
printf(“Lib未附加。\n”);
出口(1);
}
typedef bool(回调*bool\u FP\u INT)(INT i);
typedef bool(uu cdecl*FPtr)(bool_FP_INT FP,INT i);
FPtr TestCallBack=(FPtr)GetFuncAddress(hLib,“TestCallBack”);
TestCallBack((BOOL_FP_INT)VBCallBack,255);
返回0;
}
bool回调VBCallBack(int值)
{
printf(“\n使用参数%d调用回调”,值);
返回true;
}
布尔附属图书馆(作废)
{
//获取IPC dll库的变量。
std::字符串dllName;
/*---首先,链接到IPC dll库或报告失败---*/
dllName=”
// PinvokeTester.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
#include <cstdlib>
#include <string.h>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <Windows.h>
#define PINVOKELIB_API __declspec(dllimport)
HINSTANCE hLib; // Windows DLL handle
bool CALLBACK VBCallBack( int value );
bool AttachLibrary( void );
void * GetFuncAddress( HINSTANCE hLib, const char* procname );
int main(int argc, char* argv[])
{
if ( !AttachLibrary() )
{
printf( "Lib did not attach.\n" );
exit(1);
}
typedef bool (CALLBACK *BOOL_FP_INT)(int i );
typedef bool (__cdecl *FPtr)(BOOL_FP_INT fp, int i );
FPtr TestCallBack = (FPtr)GetFuncAddress( hLib, "TestCallBack" );
TestCallBack( (BOOL_FP_INT)VBCallBack, 255 );
return 0;
}
bool CALLBACK VBCallBack( int value )
{
printf( "\nCallback called with param: %d", value);
return true;
}
bool AttachLibrary( void )
{
// Get a var for the IPC-dll library.
std::string dllName;
/*--- First, link to the IPC-dll library or report failure to do so. ---*/
dllName = ".\\PinvokeLib";
if ( NULL == (hLib = LoadLibraryA( dllName.c_str() )) )
{
printf( "\nERROR: Library \"%s\" Not Found or Failed to Load. \n\n", dllName.c_str() );
printf( "\"%s\"\n", GetLastError() );
return false;
}
return true;
}
//=====================================================================
void * GetFuncAddress( HINSTANCE hLib, const char* procname )
{
void * procAddr = NULL;
procAddr = (void *)GetProcAddress( hLib, procname );
// If the symbol wasn't found, handle error ---------------------
if ( NULL == procAddr )
{
std::cout << "ERROR: Could not get an address for the \""
<< procname << "\" function. : "
<< GetLastError() << std::endl;
exit( 7 );
procAddr = (void*)NULL;
}
return procAddr;
}