DLL 参数为string类型详解

如果,就是你在Delphi当中使用的DLL。那么可以直接返回ARRAY   OF   CHAR。  
   
  这种类型是建立在全局堆上的,不会被收回,而且有引用计数保证在无人使用的时候收回。  
   
  如果你的DLL要被其他开发工具开发的程序共用的,那么不能返回ARRAY   OF   CHAR,你只能返回Pointer,并且要copy一个副本返回,否则会被收回导致指针无效。  
   
  通常,需要返回一个复杂的数据块我们不是用返回值来返回的,除非是建立在堆栈中的数据,比如一个结构。需要返回复杂数据,通常是调用者传入一个指针和缓冲区大小的整数值。函数将内容复制到调用者给出的缓冲区中,这对于动态长度的数据特别合适。为什么这么做呢?因为如果是返回值返回缓冲区指针,那么意味着是函数创建的缓冲区,而调用者却有释放缓冲区的义务,这是不合理的,因为不同的编译器产生的缓冲区结构是不一样的,会造成内存泄露。基本原则是谁创建谁释放,所以,通常由调用者传入一个缓冲区指针,而函数仅仅使用缓冲区。函数返回值通常指出缓冲区中填入了多少数据,或者指出一个所需的正确缓冲区的大小。  
   
  还有一种作法,就是你把ARRAY   OF   CHAR类型包装出一个interface返回值是包装好的对象的interface,这种做法符合对象原则,interface不用担心回收问题,它会自动收回的,对于调用者来说,使用interface是很方便的。  
   
  如果传送的数据结构特别大,复制很费时。那么我们一般使用Stream。  
   
  Stream的问题是没有统一的标准,你应该封装一个Stream的interface返回给调用者,使用Stream的方式可以避免数据被反复的复制,使用Stream可以大大提高效率。  
   
  比如将一个文件数据从Socket发送出去,如果直接打开文件复制内容到内存中,然后用Socket发送是费时的,使用Stream可以让Socket自己直接去从文件中复制数据,这样减少一次数据复制过程。此外如果文件需要加密传送,那么使用Stream就特别有效了。  
   
  上面漏了一点,就是返回值直接使用array   of   char时候,需要添加ShareMem单元在uses第一位置,同时发布的时候带上BORLANDMM.DLL这个DLL。  
   
  我不认为这是必须的,可能是为了兼容win95才这么麻烦吧。  
   
  默认的存储管理器源代码在source/rtl/sys/getmem.inc中。Delphi内存管理器用VirtualAlloc分配内存,内存分配表用LocalAlloc分配的  
   
  但是,我觉得在win32上不区分局部堆和全局堆,只有老的win16才会造成麻烦。DLL如果又调用了一次内存初始化的函数,那么也没关系,只要DLL一直在内存中不卸载,也不会造成麻烦。当然DLL如果是动态加载的,那么DLL卸载的时候很可能释放了正在exe中使用的内存块。  
   
  这个问题,还需要查证。如果不是动态加载DLL,那么我想什么问题都不会有。  
   
  DLL卸载或者exe退出的时候就会释放所有在DLL和EXE中分配的内存。  
   
  这样的话就很罗嗦,不过也正常,DLL都释放了,从DLL调用得到的内存还会存在吗?只要稍微注意一下使用方式就没事了。  
   
  但是,在win32下,绝对不会因为你在DLL中分配内存导致exe中不可用的情况出现。所以感觉那个ShareMem在win32下没有什么用处,除非是为了防止DLL卸载造成分配内存不可用。

对于string来说,他就是一个array   of   char,结构完全一致。  
   
  我上面说了,如果返回值是string这样的在全局堆分配的对象,那么只要DLL不卸载不会产生任何问题。  
   
  在你的函数中,你用了一个局部变量D来存放从DLL中返回的string。这个局部变量会在函数结束时自动释放它所引用的string对象的计数(这是编译器自动生成的代码),而这时DLL已经被卸载了,它所分配的内存已经不存在了,当然会出错!   
    
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果C++ DLL参数是指针类型,那么在C#中调用该DLL时,需要使用平台调用(P/Invoke)技术,并且需要特别注意C++和C#之间的内存管理问题。具体步骤如下: 1. 在C++中,使用`__declspec(dllexport)`关键字导出函数,例如: ``` __declspec(dllexport) void MyFunction(int* intPtr); ``` 2. 在C#中,使用`DllImport`特性声明导出函数及其参数,例如: ``` using System.Runtime.InteropServices; [DllImport("MyCppDll.dll")] public static extern void MyFunction(IntPtr intPtr); ``` 3. 在C#中,使用`Marshal.AllocHGlobal`方法分配一段内存,并使用`Marshal.WriteInt32`方法将C#中的整数值写入该内存中,例如: ``` int myInt = 123; IntPtr intPtr = Marshal.AllocHGlobal(sizeof(int)); Marshal.WriteInt32(intPtr, myInt); ``` 4. 在C#中,调用C++ DLL中的函数,并传入指针参数,例如: ``` MyFunction(intPtr); ``` 5. 在C++中,使用指针访问该内存,并读取或修改其中的值,例如: ``` void MyFunction(int* intPtr) { int myInt = *intPtr; *intPtr = myInt * 2; } ``` 6. 在C#中,使用`Marshal.ReadInt32`方法读取C++函数中修改后的整数值,例如: ``` int resultInt = Marshal.ReadInt32(intPtr); ``` 7. 在C#中,释放用于存储整数值的内存,例如: ``` Marshal.FreeHGlobal(intPtr); ``` 需要注意的是,由于C++和C#使用不同的内存管理方式,需要特别小心对象的创建和销毁,以避免内存泄漏和崩溃等问题。另外,如果C++函数中的参数是指向对象的指针,需要特别注意指针所指向的内存是否已经正确释放,否则也可能会导致内存泄漏和崩溃等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值