跳至正文
首页 » 博客 » Exploring Interop Communication

Exploring Interop Communication

1.导言

信不信由你,20世纪90年代仍有许多项目开始进行原始开发。这主要是因为不可能完全从旧的编程语言和环境中迁移。因此,为了管理这一点,一个好主意可能是开发和集成写在.NET框架。有几种跑步方式。NET代码,但在本文中,我们将重点介绍两种方法:

C /CLI ·

·非托管导出

下图显示了我们的示例的架构。在这篇文章中,我们将使用名为Intercom.Logger的单个库来标准化整个应用程序中的日志记录方法。该库使用流行的log4net库写日志消息。Intercom.Logger在任何托管代码中都可以成功使用,但我们将在C应用程序中使用它。

1 -体系结构图

2.创建对讲解决方案

出于本文的目的,有必要创建一个名为Intercom的新解决方案,其中包含两个项目: Intercom.Logger和Intercom.Client。

对讲机记录器

Intercom.Logger

是负责附加日志文件的托管库。为此,将使用名为log4net的外部库。

1.打开Visual Studio并创建一个名为对讲机对讲机记录器类库项目。

2 -创建对讲解决方案和Intercom.Logger类库。

2。使用NuGet为Intercom.Logger安装log4net。

3– Log4Net参考。

3.在项目Intercom.Logger中创建以下类。

命名空间 对讲机记录器

{

使用 log4net;

使用 log4net<span style="background-image:none;background-repeat:repeat;background-attachment: 滚动; 背景-位置: 0% 0%;mso-高亮: 白色; ">附加器;

使用 log4net核心;

使用 log4net布局;

使用<span style="background-image:none;background-repeat:repeat;background-attachment:scroll;background-pos位置: 0% 0%;mso-突出显示: 白色; ">log4net存储库层次结构;

公共 静态 记录器

{

<span style="font-size:9.5pt;"> 私有 静态 只读 ILog MyLog;

静态 记录器

()

{

<span style = “背景-图像: 无; 背景D-repeat: 重复; 背景-附件: 滚动; 背景-位置: 0% 0%;mso-高亮: 白色; “>var层次结构 = (层次结构)LogManagerGetRepository();

PatternLayoutpatternLayout =新建 PatternLayout();

&nbsp;patternLayout。转换模式=“% date [% thread] %-5级别 % 记录器-% message % newline”;

patternLayout。ActivateOptions();

FileAppender附加器 =新建 FileAppender();

<span style="background-image:none;background-repeat:repeat;background-attachment:scroll;background-position:0% 0%;mso-highlight: 白色; ">appender。文件=@ “Logs.txt”;

appender。布局= patternLayout;

appender。ActivateOptions();

层次结构。<span style = “背景-图像: 无; 背景-重复: 重复; 背景-附件: 滚动; 背景-位置: 0% 0%;mso-突出显示: 白色;”>AddAppender(附加人);

层次结构。等级=等级信息;

层次结构。已配置=<span style="color:# 0000ff;">true;

MyLog=LogManagerGetLogger(字符串);

}

<span style = “背景-图像: 无; 背景-重复: 重复; 背景-附件: 滚动; 背景-位置: 0% 0%;mso-突出显示: 白色;”>公共 静态 无效 日志(字符串消息)

{

MyLog信息(消息);

}

<span style="background-image:none;background-repeat: 重复; 背景-附件: 滚动; 背景-位置: 0% 0%;mso-高亮: 白色; ">}

}

4

记录器类。

对讲机客户端

Intercom.Client

是需要日志记录功能的本机Win32应用程序。

1。在上一节创建的解决方案中,添加一个名为Intercom.Client的新C Win32控制台应用程序项目。

5 -对讲机.客户端

2。将Windows.h包含在stdafx.h头文件中。

// stdafx.h : include file对于标准系统包含文件,

// 或项目特定的包含文件,这些文件经常使用,但使用

// 不经常更改

//

# pragma 一次

<span style = “背景-图像: 无; 背景-重复: 重复; 背景-附件: 滚动; 背景-位置: 0% 0%;mso-突出显示: w海特; “># 包括 “targetver.h”

# 包括 <stdio.h>

# 包括 <tchar.h>

<span style="background-image:none;background-repeat:repeat;background-attachment:scroll;background-pos位置: 0% 0%;mso-突出显示: 白色; ">// TODO: 在此处引用程序所需的其他标头

# 包括 <Windows.h>

6– stdafx.h头文件内容。

3.创建互操作项目

创建对讲解决方案后,有两个独立的组件:

·Intercom.Client非托管本机Win32控制台应用程序

·对讲机。记录器管理。NET框架类库

目标是使用Intercom.Logger应用程序中的库公开的Intercom.Logger记录功能。Intercom.Client本身是一个非托管应用程序,因此它不能直接引用和调用Intercom.Logger有必要创建某种互操作/代理库。

7 -已实现的组件。

Intercom.Logger.UnmanagedExports

非托管导出是向非托管本机代码公开托管C # 代码的一种方法。主要思想是将已经编译的模块反编译为IL代码,更改模块的VTable和VTableFixup表并重新编译DLL。通过使用名为UnmanagedExports的NuGet包,可以对开发人员不可见地执行此操作。该包中包含具有dlilexport属性的库和自动更改模块表的MSBuild项目。

1。在对讲解决方案中,添加一个名为Intercom.Logger.UnmanagedExports的新C # 类库项目。

8 -添加Intercom.Logger.UnmanagedExports项目。

2。对于新创建的项目,安装名为UnmanagedExports的NuGet包。

9 -安装UnmanagedExports包。

3.添加参考Intercom.Logger

10 -添加Intercom.Logger参考。

4.创建LoggerUnmanagedInterop代理类。

,向非托管本机代码公开的方法必须使用dlliexport特性进行修饰。

命名空间 对讲机记录器UnmanagedExports

{

# 区域使用

使用 系统运行时<span style="backgr声音-图像: 无; 背景-重复: 重复; 背景-附件: 滚动; 背景-位置: 0% 0%;mso-突出显示: 白色; ">。InteropServices;

使用 RGieseckeDllExport;

# endregion

公共 静态<span style="background-image:none;background-repeat:repeat;background-attachment: 滚动; 背景-位置: 0% 0%;mso-高亮: 白色; "> LoggerUnmanagedInterop

{

[DllExport(“LoggerUnmanagedInterop_Log”,调用约定=调用约定StdCall)]

<span style="background-image:none;background-重复: 重复; 背景-附件: 滚动; 背景-位置: 0% 0%;mso-高亮: 白色; ">公共 静态 无效 日志(

[元帅(UnmanagedTypeLPStr)]字符串消息)

{

<span style="background-image:none;background-repeat:repeat;background-attachment:scroll;background-position:0% 0%;mso-highlight:white;"> Logger.Log (消息);

}

}

}

11– LoggerUnmanagedInterop类。

5.添加以下生成后事件命令,将二进制文件复制到Intercom.Client的输出目录中。

复制 $(TargetDir)* $(SolutionDir)$ (配置) \

12 -添加后生成事件。

6.在生成设置中,将所有配置的平台目标更改为x86。

7。编辑UnmanagedExports程序集公开的Interop.Client. cpp主过程和调用方法。

# 包括 “stdafx.h”

// 定义公开过程的类型。

typedef 无效(回拨*日志) (字符消息 []);

<span style="background-image:none;background-repeat:repeat;background-附件: 滚动; 背景-位置: 0% 0%;mso-突出显示: 白色; ">

智力 _tmain()

{

// 加载Intercom.Logger.UnmanagedExports.dll

HMODULEhUnmanagedExports = LoadLibraryW (文本(“Intercom.Logger.UnmanagedExports.dll”));

<span style="background-image:none;background-repeat:repeat;background-attachment:sc滚动; 背景-位置: 0% 0%;mso-高亮: 白色; "> 如果 (hUnmanagedExports = = NULL ){

printf_s(

“未能加载Intercom.Logger.UnmanagedExports.dll”) );

回报

-1;

}

<span style = “background-image:none;background-repeat:repeat;back地面-附件: 滚动; 背景-位置: 0% 0%;mso-突出显示: 白色; “>// 加载ManagedLogger_Log过程。

日志日志 = (日志) GetProcAddress(hUnmanagedExports,“LoggerUnmanagedInterop_Log”);

如果(日志 = =NULL) {

printf_s (“LoggerUnmanagedInterop_Log过程的地址未知”<span style="background-image:none;background-repeat:repeat;background-attachment: 滚动; 背景-位置: 0% 0%;mso-高亮: 白色; "> );

回报

-1;

}

/// 调用公开的过程。

日志 (

消息记录”);

<span style = “mso-tab-count:1;”> 返回0;

}

13 -使用暴露的托管过程在非托管C代码。

8.构建解决方案。

9。导航到根解决方案目录中的Release/Debug文件夹。该目录应包含Intercom. client.exe和由Intercom.Logger.UnmanagedExports库的build-event复制的文件

14– Release/Debug目录。

执行Intercom.Client.exe后,应创建日志文件。

15 -执行结果。

从现在开始,本机程序Intercom.Client通过调用Intercom.Logger.UnmanagedExports中导出的过程来使用Intercop.logging中的日志记录功能。

下图显示了如何使用UnmanagedExports实现架构。Intercom.Logger.UnmanagedExports支持动态DLL加载的任何语言都可以使用: C,C,Clarion,VBA等。

16 -已实现的组件。

对讲机.Logger.CLI

暴露的第二种方式。NET方法的本地代码是通过创建一个C /CLI库。C /CLI是一种语言规范,旨在取代C的托管扩展。可以说,用C /CLI编写的库是C和C # 的一种混合体。

1。添加一个名为 “ Intercom.Logger.CLI ” 的新项目

17 -添加CLI项目。

2。添加参考Intercom.Logger

18 -添加Intercom.Logger参考。

19 -添加Intercom.Logger参考。

3。将CliLog函数头添加到文件Intercom.Logger.CLI.h

# pragma 一次

使用 命名空间的

系统;

extern_declspec “C” (dLleexport) 无效 __stdcall CliLog( char message[]);

20– Intercom.Logger.CLI.

头文件。

4.在文件Intercom.Logger.CLI.cpp中实现CliLog功能

# 包括 “stdafx.h”

# 包括 “Intercom.Logger.CLI.h”

无效 __stdcallCliLog (字符 <span style="color:#808080;"> 消息[])

{

对讲机:: 记录器::记录器日志 (gcnew 字符串(信息));

}

21– CliLog函数实现。

5.使用名为exports. def的导出过程定义创建一个文件,内容如下:

库对讲.Logger.CLI.DLL

出口

CliLog @ 4

22 -exports.Def文件内容。

该文件包含将导出的过程的定义。表达式 @ 4表示参数中采用的字节数。在这种情况下,参数消息 [] 是32位指针,所以它的大小等于4个字节。

确保文件属性如下所示:

23 -exports.Def文件属性。

exports.Def文件也应包含在项目属性中,如下图所示:

24 -包括exports.Def在项目属性中。

6.将以下代码添加到Intercom.Client.cpp中:

// 加载对讲机.Logger.CLI.dll

HMODULEhCli = LoadLibraryW (文本(“Intercom.Logger.CLI.dll”));

如果(hCli = =NULL) {

printf_s (“无法加载Intercom.Logger.CLI.dll”);

<span style="background-image:none;background-repeat:repeat;background-attachment:scroll;background-位置: 0% 0%;mso-高亮: 白色; ">返回-1;

}

// 加载日志过程。

日志logCli = (日志) GetProcAddress(hCli,“CliLog”);

如果(logCli = =NULL<span style="background-image:none;background-repeat:repeat;background-attachment:scroll;background-p位置: 0% 0%;mso-突出显示: 白色; "> ){

printf_s(” 日志过程地址未知 “

);

回报

-1;

}

// 调用公开的CLI过程。

logCli(

“消息从CLI”);

7。重建并运行Intercom.Client项目。

CLI和客户端二进制文件将自动复制到同一目录。在这种情况下,不需要添加任何生成后事件。运行后,文件Logs.txt还应包含通过调用CliLog() export添加的消息。

下图显示了已经实现的功能。这一次, Intercom.Client的应用程序使用CLI库执行Intercom.Logger中的托管代码。

25 -体系结构图。

4.总结

本文的主要目的是展示如何调用managed.NET代码从非托管本机C应用程序。这些示例非常简单,但可以为扩展用C /Clarion/VBA或其他可能受益于DLL导出的语言编写的企业应用程序奠定良好的基础。Log() 只包含一个参数: char数组,但它可以传递其他类型和整个结构。更多信息可以在下面列出的网站中找到,您也可以找到本文中使用的来源的链接:

DLL导出查看器可用于浏览DLL导出:
http://www.nirsoft.net/utils/ dll_export_viewer.html

有关UnmanagedExports的详细信息:

https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports

https://www.nuget.org/packages/UnmanagedExports

要查看此项目的源代码,请下载所有文档的zip文件

想要构建具有高性能控件的桌面、移动或web应用程序?下载终极免费试用现在,看看它能为你做什么!

</p