当前位置: 首页 > 编程语言 > C#

如何将结构从C#发送到VB6以及从VB6发送到C#?Share

时间:2023-04-11 11:04:38 C#

如何将结构从C#发送到VB6以及从VB6发送到C#?我需要将结构从C#发送到VB6应用程序,修改VB6中的数据,然后通过Windows消息传递结果。我应该怎么办?我能够使用PostMessage来回发送基本整数(在C#中使用DllImport并使用Windows消息传递注册vb6应用程序),但需要发送更多结构化数据,包括字符串、整数和小数。寻找最简单的解决方案来实现来回传递结构化数据。VB6类型的基本示例PublicTypeudtSessionDataSessionIDAsIntegerSessionNameAsStringMinValAsCurrencyPctCompleteAsDoubleNValAsIntegerProcessedFlagAsBooleanProcessedDateAsDateLengthAsIntegerEndType警告:人们可能有兴趣在开始项目之前注意你的其他问题.REF:如何从VB6和C#发送/接收Windows消息?如此处和您的其他帖子中所述,您应该重新考虑尝试使这项工作成功。特别是,即使您对这里的技术没有问题,您的同事或其他可能需要维护您的代码的人也会有一段非常糟糕的时光。请注意,在VB6中调试过程也非常困难-经常保存和使用大量断点!如果您的代码中有错误,预计会发生很多崩溃。此外,不应将PostMessage与此技术一起使用。这将需要更多的清理工作。解决方案:我附上了一个示例,它可以返回一个仅包含字符串和整数类型的结构。完成这项工作需要很多活动部件。我们将深入探讨从C#到VB的过程,因为它比较棘手。一旦你知道如何去做,反过来就不是那么难了。首先,在C#端,您应该声明您的结构。在C#中打包结构实际上并不坏。下面是一个COM可见的C#示例类,它演示了如何包装结构。关键是在调用的两边都使用Marshal.StructureToPtr和Marshal.DestroyStructure。根据所涉及的类型,您甚至可能不必编写代码来映射这些类型。使用MarshalAs属性标记VB6的正确映射。MarshalAs中使用的枚举中的大多数项目对应于VARIANT和COM自动化中使用的不同变量类型。此处使用的缓冲区由HGlobal支持,需要在调用结束后释放。也可以在这里使用GCHandle,这需要类似的清理。MarshalAsAttribute类@MSDNMarshal.StructureToPtr方法@MSDNMarshal.DestroyStructure方法@MSDNMarshal.AllocHGlobal方法@MSDNMarshal.FreeHGlobal方法@MSDNusingSystem;使用System.Collections.Generic;使用系统文本;使用System.Runtime.InteropServices;namespaceHostLibrary{publicstructTestInfo{[MarshalAs(UnmanagedType.BStr)]公共字符串标签;[MarshalAs(UnmanagedType.I4)]publicintcount;}[ComVisible(true)]publicinterfaceITestSender{inthostwindow{get;设置;}voidDoTest(stringsomeParameter);}[ComVisible(true)]publicclassTestSender:ITestSender{publicTestSender(){m_HostWindow=IntPtr.Zero;m_count=0;}IntPtrm_HostWindow;intm_count;#regionITestSender成员publicinthostwindow{get{return(int)m_HostWindow;}设置{m_HostWindow=(IntPtr)value;}}publicvoidDoTest(stringstrParameter){m_count++;测试信息信息;inf.label=str参数;inf.count=m_count;IntPtrlparam=IntPtr.Zero;尝试{lparam=Marshal.AllocHGlobal(Marshal.SizeOf(inf));Marshal.StructureToPtr(inf,lparam,false);//WM_APP是0x8000IntPtrretval=SendMessage(m_HostWindow,0x8000,IntPtr.Zero,lparam);}finally{if(lparam!=IntPtr.Zero){Marshal.DestroyStructure(lparam,typeof(TestInfo));元帅.FreeHGlobal(lparam);}}}#endregion[DllImport("user32.dll",CharSet=CharSet.Auto)]externpublicstaticIntPtrSendMessage(IntPtrhwnd,uintmsg,IntPtrwparam,IntPtrlparam);在VB6方面,您需要设置一种机制来拦截消息由于您的其他问题和其他地方已经详细介绍了信息,我将跳过子类化的主题。要在VB6端解压结构,您需要在每个字段中执行此操作,因为没有可用于取消引用指针值并将其转换为结构的机制。幸运的是,如果您没有在C#中另外指定,您可以期望字段成员在VB6中按4字节边界对齐。这允许我们逐个字段地工作,将项目从一种表示映射到另一种表示。首先,一些完成所有支持工作的模块代码。以下是功能和注意事项。TestInfo类型-两侧使用的结构的镜像定义。CopyMemory-可用于复制字节的win32函数。ZeroMemory-将内存重置为零字节值的win32函数。除了项目之外,我们还使用VB6中未记录的VarPtr()函数来获取项目的地址。我们可以使用它来索引VB6端的结构。有关此功能的更多信息,请参阅以下链接。如何在VisualBasic@support.microsoft.com中获取变量的地址PublicConstWM_APPAsLong=32768PrivateConstGWL_WNDPROC=(-4)PrivateprocOldAsLongTypeTestInfolabelAsStringcountAsIntegerEndTypePrivateDeclareFunctionCallWindowProcLib"USER32.DLL"别名"CallWindowProcA"_(ByVallpPrevWndFuncAsLong,ByValhWndAsLong,ByValuMsgAsLong,_ByValwParamAsLong,ByVallParamAsLong)私有声明函数SetWindowLongLib"USER32.DLL"别名"SetWindowLongA"_(ByValhWndAsLong,ByValnIndexAsLong,ByValdwNewLongAsLong)PrivateDeclareSubCopyMemoryLib"KERNEL32.DLL"别名"RtlMoveMemory"_(ByValpDstAsLong,ByValpSrcAsLong,ByValByteLenAsInteger)PrivateDeclareSubZeroMemoryLib"KERNEL32.DLL"别名"RtlZeroMemory"_(ByValpDstAsLong,ByValByteLenAsInteger)PublicSubSubclassWindow(ByValhWndAsLong)procOld=SetWindowLong(hWnd,GWL_WNDPROC,AddressOfSubWndProc)EndSub公共附属单位ubclassWindow(ByValhWndAsLong)procOld=SetWindowLong(hWnd,GWL_WNDPROC,procOld)EndSubPrivateFunctionSubWndProc(_ByValhWndAsLong,_ByValiMsgAsLong,_ByValwParamAsLong,_ByVallParamAsLong)如果hWnd=Form1.hWndThenIfiMsg=WM_APPThenDiminfAsTestInfo'复制第一个字段(标签)调用CopyMemory(VarPtr(inf),lParam,4)'复制第二个字段(计数)调用CopyMemory(VarPtr(inf)+4,lParam+4,4)DimstrInfoAsStringstrInfo="label:"&inf.label&vbCrLf&"count:"&CStr(inf.count)CallMsgBox(strInfo,vbOKOnly,"WM_APPReceived!")'清除第一个字段(标签),因为它是一个字符串CallZeroMemory(VarPtr(inf),4)'不必清除第二个字段,因为它是一个整数SubWndProc=TrueExitFunctionEndIfEndIfSubWndProc=CallWindowProc(procOld,hWnd,iMsg,wParam,lParam)EndFunction请注意,此解决方案需要发送方和接收方的合作,因为我们不想两次释放字符串字段,因此在返回控制之前清空VB6端的副本。如果您尝试为字段成员分配新值,这里会发生什么是未定义的,因此请避免编辑结构中的字段。在映射字段中,C#中的UnmanagedType.BStr直接类似于VB6中的String。UnmanagedType.I4映射到VB6中的Integer和Long。您在UDT中指定的其他字段也有等效项,但我不确定VB6中的DateTime。VB6应用程序的其余部分(形式源代码)很简单。DimCSharpClient作为新的HostLibrary.TestSenderPrivateSubCommand1_Click()CSharpClient.DoTest("HelloWorldfromVB!")EndSubPrivateSubForm_Load()CSharpClient.hostwindow=Form1.hWndModule1.SubclassWindow(Form1.hWnd)EndSubPrivateSubForm_Unload(CancelAsInteger)CSharpClient.hostwindow=0Module1.UnsubclassWindow(Form1.hWnd)EndSub现在您需要在将结构从VB6发送到C#时执行相反的操作。对于一些简单的结构,您甚至可以只发送结构本身的地址。如果需要成员控制,使用GlobalAlloc获取合适的缓冲内存,然后使用GlobalFree释放它。对于每个字段,成员复制的执行方式与从C#中打开参数的方式相同。然而,调用后的清理更简单。如果使用缓冲区,则只需在将缓冲区移交给GlobalFree之前将缓冲区中的内存清零即可。GlobalAllocfunction(Windows)@MSDNGlobalFreefunction(Windows)@MSDN当消息到达C#端时,使用Marshal.PtrToStructure()将IntPtr映射到.NET结构。Marshal.PtrToStructure方法@MSDN您必须分配一个GUID并使用MarshalAs属性。.NETCOMInterop处理转换。跟上课没多大区别。本系列文章说明了您需要做什么。您可以通过在.NET上使用P/Invoke并在VB6中导入CopyMemory来实现它,但这是一个巨大的维护灾难,我建议从类似的任何东西运行。以上是C#学习教程:如何从C#传结构到VB6,从VB6传到C#?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:

最新推荐
猜你喜欢