关于DLL中指针变量的传递方法,求非托管代码转托管的方法,详细内容见正文。

问题描述

我获得的方法是使用C#非托管指针的方法来实现的,因为VB.NET中不允许直接操作非托管指针或内存,所以必须使用Marshal来实现。=========================================C++的类库原型:DLLEXPORT_APIint__stdcallSetOsdDisplayModeEx(HANDLEhChannelHandle,intcolor,BOOLTranslucent,intparam,intnLineCount,USHORT**Format);

C++中的调用方法片段:USHORTFormat3[8][44]={{2,2,'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4',''},{2,25,'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4',''},{2,50,'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9',''},{2,75,'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9',''},{2,100,_OSD_YEAR4,'-',_OSD_MONTH2,'-',_OSD_DAY,'-',_OSD_HOUR24,':',_OSD_MINUTE,':',_OSD_SECOND,'-',_OSD_MONTH3,'-',_OSD_WEEK3,'星','期',_OSD_CWEEK1,_OSD_HOUR12,''},{2,125,'h','a','n','g','z','h','o','u','','h','i','k','v','i','s','i','o','n',''},{2,150,'杭','州','海','康','威','视',''},{2,175,'D','S','-','4','0','x','x','H','C',''}};USHORT*Format4[8];for(i=0;i<8;i++){Format4[i]=Format3[i];}...for(i=0;i<GetTotalDSPs();i++){SetOsdDisplayMode(ChannelHandle[i],255,TRUE,1,Format1,Format2);//showosdwith8rows//SetOsdDisplayModeEx(ChannelHandle[i],255,TRUE,1,8,Format4);SetOsd(ChannelHandle[i],TRUE);}

转换成C#的封装类:[DllImport("DS40xxSDK.dll")]publicstaticexternunsafeintSetOsdDisplayModeEx(IntPtrhChannelHandle,intBrightness,boolTranslucent,intparam,intnLineCount,ushort*[]Format);

C#中的调用方法片段:...ushort[,]Format={{48,16,'A',''},{48,32,'B',''}};this.UsePoints(Format);...intUsePoints(ushort[,]Format){introw=Format.GetUpperBound(0)+1;intcol=Format.GetUpperBound(1)+1;unsafe{fixed(ushort*fp=Format){ushort*[]farr=newushort*[row];for(inti=0;i<row;i++){farr[i]=fp+i*col;}returnDS40xxSDK.HikVisionSDK.SetOsdDisplayModeEx(ChannelHandle,255,true,0,2,farr);}}}

欲转换成在VB.NET中的封装:<DllImport("DS40xxSDK.dll")>_PublicSharedFunctionSetOsdDisplayModeEx(ByValhChannelHandleAsIntPtr,ByValBrightnessAsInteger,ByValTranslucentAsBoolean,ByValparamAsInteger,ByValnLineCountAsInteger,ByValiFormatAsIntPtr)AsIntegerEndFunction

下面就是请教该如何转换成使用Marshal类来实现的方法了。有哪位大虾知道,帮一下忙!

解决方案

解决方案二:
自己写了一个,但还是遇到问题!程序出错:System.Runtime.InteropServices.COMException(0x80070006):句柄无效。(ExceptionfromHRESULT:0x80070006(E_HANDLE))封装:<DllImport("DS40xxSDK.dll")>_PublicSharedFunctionSetOsdDisplayModeEx(ByValhChannelHandleAsIntPtr,ByValBrightnessAsInteger,ByValTranslucentAsBoolean,ByValparamAsInteger,ByValnLineCountAsInteger,ByValiFormatAsIntPtr)AsIntegerEndFunction

调用:PublicFunctionSetOSD(ByValTagAsString,ByValRowCountAsInteger)AsBooleanDimFormat(,)AsUShort=NewUShort(,)_{_{16,16,Asc("F"),0},_{16,32,Asc("L"),0}_}DimrowAsInteger=Format.GetUpperBound(0)+1DimcolAsInteger=Format.GetUpperBound(1)+1DimptAsNewIntPtrDimptr(row-1)AsIntPtr'申请内存pt=Marshal.AllocHGlobal(Marshal.SizeOf(GetType(IntPtr))*row)ForiAsInteger=0Torow-1'ptr(i)=Marshal.AllocHGlobal(Marshal.SizeOf(GetType(UShort))*col)ptr(i)=Marshal.UnsafeAddrOfPinnedArrayElement(Format,i)NextMarshal.Copy(ptr,0,pt,row)Dimret1AsInteger=HKDSSDK.HikVisionSDK.SetOsdDisplayModeEx(ChannelHandle,255,False,&H10200,2,pt)Dimret2AsInteger=-1DimretvalAsBooleanIfret1=0Thenret2=HKDSSDK.HikVisionSDK.SetOsd(ChannelHandle,True)Ifret2=0Thenretval=TrueElseretval=FalseEndIfElseretval=FalseEndIfForiAsInteger=0Torow-1Marshal.FreeHGlobal(ptr(i))NextMarshal.FreeHGlobal(pt)ReturnretvalEndFunction

调用成功一半,数组一部分能够能够成功封送,随后出现System.Runtime.InteropServices.COMException(0x80070006):句柄无效。(ExceptionfromHRESULT:0x80070006(E_HANDLE))
解决方案三:
根据你上面的C#用机器翻译的:PublicClassHikVisionSDK<DllImport("DS40xxSDK.dll")>_PublicSharedFunctionSetOsdDisplayModeEx(hChannelHandleAsIntPtr,BrightnessAsInteger,TranslucentAsBoolean,paramAsInteger,nLineCountAsInteger,FormatAsPointer(OfUShort)())AsIntegerEndFunctionEndClassDimFormatAsUShort(,)={{48,16,"A"C,ControlChars.NullChar},{48,32,"B"C,ControlChars.NullChar}}Me.UsePoints(Format)PrivateFunctionUsePoints(FormatAsUShort(,))AsIntegerDimrowAsInteger=Format.GetUpperBound(0)+1DimcolAsInteger=Format.GetUpperBound(1)+1DimfarrAsPointer(OfUShort)()=NewPointer(OfUShort)(row-1){}ForiAsInteger=0Torow-1farr(i)=fp+i*colNextReturnDS40xxSDK.HikVisionSDK.SetOsdDisplayModeEx(ChannelHandle,255,True,0,2,farr)EndFunction

解决方案四:
引用2楼的回复:

根据你上面的C#用机器翻译的:VB.NETcodePublicClassHikVisionSDK<DllImport("DS40xxSDK.dll")>_PublicSharedFunctionSetOsdDisplayModeEx(hChannelHandleAsIntPtr,BrightnessAsInteger,Translu……

VB.NET中是不允许直接操作非托管的指针和内存,所以Pointer类的与指针操作相关的Box和UnBox方法都是无法使用的,所以不能像C#那样很自由的用Unsafe来操作指针和内存。
解决方案五:
似乎又有了些进展,终于知道为什么会产生:System.Runtime.InteropServices.COMException(0x80070006):句柄无效。(ExceptionfromHRESULT:0x80070006(E_HANDLE))的原因!跟踪了一下错误:atSystem.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32errorCode,IntPtrerrorInfo)atSystem.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32errorCode)atSystem.Runtime.InteropServices.Marshal.FreeHGlobal(IntPtrhglobal)其中FreeHGlobal(IntPtrhglobal)我初时考虑,是不是申请的内存被Free了,于是就注释了所有的内存资源释放语句。结果仍旧出现FreeHGlobal(IntPtrhglobal),百思不得其解。。。直到突然“垃圾回收”,是不是invoke自动回收调用了这个语句。。。结合问题出现的现象,调用似乎刚开始是正常的,后来抛出无效句柄的异常。。。看来是应该这么回事。。。但如何不让他自动回收,查了下资料。。。以下是我找到的一篇资料的片段:三、如何保证使用托管对象的平台调用成功?如果在调用平台invoke后的任何位置都未引用托管对象,则垃圾回收器可能将完成该托管对象。这将释放资源并使句柄无效,从而导致平台invoke调用失败。用HandleRef包装句柄可保证在平台invoke调用完成前,不对托管对象进行垃圾回收。例如下面:FileStreamfs=newFileStream("a.txt",FileMode.Open);StringBuilderbuffer=newStringBuilder(5);intread=0;ReadFile(fs.Handle,buffer,5,outread,0);//调用WinAPI中的ReadFile函数由于fs是托管对象,所以有可能在平台调用还未完成时候被垃圾回收站回收。将文件流的句柄用HandleRef包装后,就能避免被垃圾站回收:[DllImport("Kernel32.dll")]publicstaticexternboolReadFile(HandleRefhndRef,StringBuilderbuffer,intnumberOfBytesToRead,outintnumberOfBytesRead,refOverlappedflag);............FileStreamfs=newFileStream("HandleRef.txt",FileMode.Open);HandleRefhr=newHandleRef(fs,fs.Handle);StringBuilderbuffer=newStringBuilder(5);intread=0;//platforminvokewillholdreferencetoHandleRefuntilcallendsReadFile(hr,buffer,5,outread,0);

关键是要利用HandleRef来包装一个托管对象,该对象保存使用平台invoke(调用)传递给非托管代码的资源句柄。唉,又涨知识了,可是,怎么着手。。。当然封送的参数类型又要修改。。。<DllImport("DS40xxSDK.dll")>_PublicSharedFunctionSetOsdDisplayModeEx(ByValhChannelHandleAsIntPtr,ByValBrightnessAsInteger,ByValTranslucentAsBoolean,ByValparamAsInteger,ByValnLineCountAsInteger,ByRefiFormatAsHandleRef)AsIntegerEndFunction

但如何调用。。。还在摸索。。。又或者。。。弱弱的希望又一个大虾的出现。。。
解决方案六:
前阵子做过的给你参考下,主要是定义为指针,并分配一块内存,使用时根据指针,及长度,读出到数组中即可。祝你成功。DllImport("epcAuthorizationVb.dll",CharSet:=CharSet.Unicode)>_PublicFunctionVbepcAuthorizeEncode(ByVallpszPassword()AsByte,ByValpEncodeOutDataAsIntPtr,ByRefpOutDataLenAsUInt32)AsBooleanEndFunction'======调用例ConstOutDataBufferLenAsInteger=64'缓冲区大小,>=16且<=__BLOCK_DATA_SIZEDimpassword()AsByte=System.Text.Encoding.UTF8.GetBytes(TextBoxSend.Text)DimbufferEncodeOutDataAsIntPtr=Marshal.AllocCoTaskMem(OutDataBufferLen)'分配内存DimoutDataLenAsUInt32=OutDataBufferLen'传入缓冲区大小DimbSuccessAsBoolean=VbepcAuthorizeEncode(password,bufferEncodeOutData,outDataLen)IfbSuccessThenConsole.WriteLine("Success!outDataLenAfterCall:{0}",outDataLen)'outDataLen输出已加密字节长度DimarrEncodeOutData()AsByte=NewByte(outDataLen){}'储存输出的已加密字节i=0Whilei<outDataLenarrEncodeOutData(i)=Marshal.ReadByte(bufferEncodeOutData,i)Console.Write("{0}",arrEncodeOutData(i))System.Math.Max(System.Threading.Interlocked.Increment(i),i-1)EndWhileElseConsole.WriteLine("Fail!outDataLenAfterCall:{0}",outDataLen)EndIfMarshal.FreeCoTaskMem(bufferEncodeOutData)'释放内存'======
解决方案七:
用完后要记得,释放内存
解决方案八:
谢谢5楼的这位朋友,这个方法我已经知道了,我在前面已经尝试过类似的方法。目前的问题是,封送过去后,出现调用COM句柄无效的问题,可能是跟GC有关,正在头疼中。。。

时间: 2024-09-16 10:07:35

关于DLL中指针变量的传递方法,求非托管代码转托管的方法,详细内容见正文。的相关文章

如何在Dll中导出STL类

简介:本文详述在DLL中导出stl类及包含stl的类的方法.例子源码 Dll无法直接导出泛型模板(generalized template),因此,如果要导出stl类,则模板必须先实例化(instantiated).另外,如果导出的STL类使用了其他STL类,那么这些其他类必须同时被导出.目前stl中唯一能够被导出的容器是vector,其他容器(如map.set.queue.list.deque)都因包含嵌套类而不能被导出. 导出STL类的步骤: 在Dll和exe文件中,用同样版本的c运行库链接

深入理解JS中的变量及作用域、undefined与null

 本篇文章主要是对JS中的变量及作用域.undefined与null进行了详细的介绍,需要的朋友可以过来参考下,希望对大家有所帮助 Situation One   代码如下: <script> var i; //全局变量 //方法名是camel命名法 //方法里面的变量是局部变量   function sayHello(){ var x=100; alert(x); x++; } sayHello(); //输出100 alert(x); //报错,因为x是局部变量,访问不到 </scr

关于显示数据库中某条记录详细内容的问题

问题描述 各位前辈.本人第一次开发asp.net的网站.自学很辛苦.很多问题没有经验.现在遇到一个问题.情况这样.在做类似论坛的一个功能(access数据库.其中的字段为主题.内容.id等).从数据库中取出所有记录的主题.通过repeater绑定显示出来已经搞定.现在是想能点击某个主题能显示出相应主题记录的内容.也就是说要实现类似csdn这样的功能.点击帖子列表中的某个帖子主题,打开另一个页面显示详细内容...页面传值等问题也已经搞定.没搞定的问题就是该如何显示内容?不知道要绑定到什么控件显示合

java中 的变量在方法间的传递权限问题

问题描述 java中 的变量在方法间的传递权限问题 我现在定义了方法1(),在该方法里用了scanner获取了一个整数a,对这个整数进行了相关操作,返回了一个字符串s,但是我现在定义了一个方法2(),该方法要接收方法1()返回的字符串s,该方法同时也要用到方法1()中scanner获取的那个整数a,进行操作后返回一个整数b(b用main()函数接收),那么问题就来了,方法1只能返回一个字符串s,那么方法2()怎么获取方法1()的那个用scanner接收到的整数呢?我的想法是将方法1()中的sca

DLL中传递STL参数

以下是自己在调测代码过程出现问题后,搜索出来的资料,虽然很乱,但明白了在跨DLL传递stl中的容器类对象时存在问题的原因及解决办法,故保存之. STL跨平台调用会出现很多异常,你可以试试. STL使用模板生成,当我们使用模板的时候,每一个EXE,和DLL都在编译器产生了自己的代码,导致模板所使用的静态成员不同步,所以出现数据传递的各种问题,下面是详细解释. 原因分析: 一句话-----如果任何STL类使用了静态变量(无论是直接还是间接使用),那么就不要再写出跨执行单元访问它的代码. 除非你能够确

DLL中传递STL参数,vector对象作为dll参数传递等问题(转)

STL跨平台调用会出现很多异常,你可以试试. STL使用模板生成,当我们使用模板的时候,每一个EXE,和DLL都在编译器产生了自己的代码,导致模板所使用的静态成员不同步,所以出现数据传递的各种问题,下面是详细解释. 原因分析:一 句话-----如果任何STL类使用了静态变量(无论是直接还是间接使用),那么就不要再写出跨执行单元访问它的代码. 除非你能够确定两个动态库使用的 都是同样的STL实现,比如都使用VC同一版本的STL,编译选项也一样.强烈建议,不要在动态库接口中传递STL容器!! STL

向ATL DLL中传递C++对象

简介 几个星期以前,我拼命的寻找一个能够通过COM接口传递C++对象的例子,但是,没有找到.这就是我发表这篇文章的原因. 向ATL的DLL中传递一个C++对象参数并不是非常之难,但是,当然也会有点难度,也很有趣. 在开始一个工程以前,首先你得确信客户机和服务器组件都是适应C++的程序,其次,你必须知道怎样设置你的客户机和服务器. 接口的局限性 COM技术要求客户机和服务器高度的分离,这是通过接口实现的,但是问题出在:接口的方法中只提供了有限个参数数据类型,如果这个接口是基于IDispatch的,

delphi-Delphi中,怎么获取DLL中定义的变量

问题描述 Delphi中,怎么获取DLL中定义的变量 可以使用动态加载或静态加载的方式使用DLL中的方法,但是怎么能够获取DLL中定义的变量来使用它呢? 解决方案 要明确2个概念: 1.Dll是EXE的一个变种形态.它是可执行的. 2.Dll虽然由EXE调用,但执行读入内存后,Dll与EXE分别是独立的内存区域,相互不联系的.二者的数据(变量等)不能传递的. 为了能让Dll是EXE通联,往往可以通过以下几种方式建立联系. 1.发消息,它是单相思,消息发出后,对方知道否,接受了吗,不得而知. 2.

C++指针变量在PHP中怎么表示?

问题描述 C++指针变量在PHP中怎么表示? 3) int rf_get_status(HANDLE icdev,unsigned char *_Status); 功 能: 获取读写器的版本号. 参 数: icdev: rf_init()返回的设备描述符 _Status: 返回读写器版本信息,长度为18字节 返 回: =0: 成功 <>0: 失败 例: int st; unsigned char status[19]; st=rf_get_status(icdev,status); 解决方案