Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/137.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从VB向DLL中的外部C函数传递指针 我是一个C++(MSVC)编写者,VB新手,试图帮助一个专家,以前从未做过这个任务。p> 我们希望开发C/C++和VB应用程序,使用C++编写的带有C外部API函数的DLL。C++程序运行正常。这是我们遇到困难的地方_C++_Vb.net_Dll - Fatal编程技术网

从VB向DLL中的外部C函数传递指针 我是一个C++(MSVC)编写者,VB新手,试图帮助一个专家,以前从未做过这个任务。p> 我们希望开发C/C++和VB应用程序,使用C++编写的带有C外部API函数的DLL。C++程序运行正常。这是我们遇到困难的地方

从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

DLL提供一个
外部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;
}