是否可以从托管c++ /CLI项目中正常运行非托管c++ ?

时间:2022-09-01 09:29:20

I'm in the process of wrapping a pure unmanaged VC++ 9 project in C++/CLI in order to use it plainly from a .NET app. I know how to write the wrappers, and that unmanaged code can be executed from .NET, but what I can't quite wrap my head around:

我正在用c++ /CLI包装一个纯粹的未管理的VC+ 9项目,以便从。net应用程序中简单地使用它。

  1. The unmanaged lib is a very complex C++ library and uses a lot of inlining and other features, so I cannot compile this into the /clr-marked managed DLL. I need to compile this into a seperate DLL using the normal VC++ compiler.

    非托管库是一个非常复杂的c++库,使用了很多内联和其他特性,因此我无法将其编译成/clr标记的托管DLL。我需要使用普通的vc++编译器将它编译成一个独立的DLL。

  2. How do I export symbols from this unmanaged code so that it can be used from the C++/CLI project? Do I mark every class I need visible as extern? Is it that simple or are there some more complexities?

    如何从这个非托管代码导出符号,以便它可以从c++ /CLI项目中使用?我是否标记每一个我需要可见的类为extern?是简单还是复杂?

  3. How do I access the exported symbols from the C++/CLI project? Do I simply include the header files of the unmanaged source code and will the C++ linker take the actual code from the unmanaged DLL? Or do I have to hand write a seperate set of "extern" classes in a new header file that points to the classes in the DLL?

    如何访问从c++ /CLI项目导出的符号?我是否只包含非托管源代码的头文件,而c++链接器将从非托管DLL中获取实际代码?或者,我必须在一个指向DLL中的类的新头文件中编写一个“extern”类的独立集吗?

  4. When my C++/CLI project creates the unmanaged classes, will the unmanaged code run perfectly fine in the normal VC9 runtime or will it be forced to run within .NET? causing more compatibility issues?

    当我的c++ /CLI项目创建非托管类时,非托管代码会在正常的VC9运行时完美运行吗?还是会*在。net中运行?导致更多的兼容性问题?

  5. The C++ project creates lots of instances and has its own custom-implemented garbage collector, all written in plain C++, it is a DirectX sound renderer and manages lots of DirectX objects. Will all this work normally or would such Win32 functionality be affected in any way?

    c++项目创建了许多实例,并拥有自己的自定义实现的垃圾收集器,所有这些都是用普通的c++编写的,它是一个DirectX声音渲染器,管理大量的DirectX对象。所有这些工作正常吗?或者Win32功能会受到任何影响吗?

3 个解决方案

#1


7  

You can start with an ordinary native C++ project (imported from, say, Visual Studio 6.0 from well over a decade ago) and when you build it today, it will link to the current version of the VC runtime.

您可以从一个普通的本地c++项目(从十多年前的Visual Studio 6.0导入)开始,当您今天构建它时,它将链接到当前版本的VC运行时。

Then you can add a single new foo.cpp file to it, but configure that file so it has the /CLR flag enabled. This will cause the compiler to generate IL from that one file, and also link in some extra support that causes the .NET framework to be loaded into the process as it starts up, so it can JIT compile and then execute the IL.

然后您可以添加一个新的foo。cpp文件,但要配置该文件,使其具有/CLR标志。这将导致编译器从一个文件生成IL,并链接一些额外的支持,使. net框架在启动时加载到进程中,这样它就可以JIT编译然后执行IL。

The remainder of the application is still compiled natively as before, and is totally unaffected.

应用程序的其余部分仍然像以前一样本地编译,并且完全不受影响。

The truth is that even a "pure" CLR application is really a hybrid, because the CLR itself is (obviously) native code. A mixed C++/CLI application just extends this by allowing you to add more native code that shares the process with some CLR-hosted code. They co-exist for the lifetime of the process.

事实上,即使是“纯”的CLR应用程序也是一种混合,因为CLR本身(显然)是本地代码。混合的c++ /CLI应用程序允许您添加更多的本地代码,这些代码与一些clr托管的代码共享进程。它们在整个过程*存。

If you make a header foo.h with a declaration:

如果你做一个页眉foo。h和声明:

void bar(int a, int b);

You can freely implement or call this either in your native code or in the foo.cpp CLR code. The compiler/linker combination takes care of everything. There should be no need to do anything special to call into native code from within your CLR code.

您可以在本地代码或foo中*地实现或调用它。cpp CLR代码。编译器/链接器组合负责一切。从CLR代码中调用本地代码不需要做任何特殊的事情。

You may get compile errors about incompatible switches:

您可能会收到关于不兼容开关的编译错误:

  • /ZI - Program database for edit and continue, change it to just Program database
  • /ZI -用于编辑和继续的程序数据库,将其更改为程序数据库
  • /Gm - you need to disable Minimal rebuild
  • /Gm -你需要禁用最小重构
  • /EHsc - C++ exceptions, change it to Yes with SEH Exceptions (/EHa)
  • /EHsc - c++异常,在SEH异常的情况下将其更改为Yes (/EHa)
  • /RTC - Runtime checks, change it to Default
  • /RTC -运行时检查,将其更改为默认值。
  • Precompiled headers - change it to Not Using Precompiled Headers
  • 预编译头-更改为不使用预编译头
  • /GR- - Runtime Type Information - change it to On (/GR)
  • /GR- -运行时类型信息-将其更改为On (/GR)

All these changes only need to be made on your specific /CLR enabled files.

所有这些更改只需要在特定/CLR启用的文件上进行。

#2


1  

As mentioned from Daniel, you can fine-tune your settings on file level. You can also play with '#pragma managed' inside files, but I wouldn't do that without reason.

正如Daniel提到的,您可以在文件级别上微调您的设置。您还可以在内部文件中使用“#pragma managed”,但是我没有理由这样做。

Have in mind, that you can create a complete mixed mode assembly. That means, you can compile your native code unchanged into this file PLUS some C++/CLI wrapper around this code. Finally, you will have the same file as native Dll with all your exported native symbols AND as full-fledged .NET assembly (exposing C++/CLI objects) at the same time!

请记住,您可以创建一个完整的混合模式程序集。这意味着,您可以将未更改的本机代码编译到此文件中,并在此代码周围加上一些c++ /CLI包装器。最后,您将同时拥有与本机Dll相同的文件,其中包含所有导出的本机符号和完整的.NET程序集(暴露c++ /CLI对象)!

That also means, you have only to care about exports as far as native client code outside your file is considered. Your C++/CLI code inside the mixed dll/assembly can access the native data structures using the usual access rules (provided simply by including the header)

这也意味着,只要考虑到文件之外的本机客户端代码,您只需关心导出。混合dll/程序集中的c++ /CLI代码可以使用通常的访问规则(仅通过包含header提供)访问本机数据结构

Because you mentioned it, I did this for some non-trivial native C++ class hierarchy including a fair amount of DirectX code. So, no principal problem here.

因为您提到了它,所以我为一些非平凡的本地c++类层次结构做了这个工作,包括相当数量的DirectX代码。所以,这里没有主要问题。

I would advise against usage of pInvoke in a .NET-driven environment. True, it works. But for anything non-trivial (say more than 10 functions) you are certainly better with an OO approach as provided by C++/CLI. Your C# client developers will be thankful. You have all the .NET stuff like delegates/properties, managed threading and much more at your finger tips in C++/CLI. Starting with VS 2012 with a somewhat usable Intellisense too.

我建议不要在. net驱动的环境中使用pInvoke。真的,它的工作原理。但是对于任何重要的东西(比如超过10个函数),使用c++ /CLI提供的OO方法肯定会更好。您的c#客户开发人员将感激不尽。你拥有所有的。net的东西,比如委托/属性,托管线程,以及更多的在c++ /CLI中的手指技巧。从VS 2012开始,也有一些可用的智能感知。

#3


0  

You can use PInvoke to call exported functions from unmanaged DLLs. This is how unmanaged Windows API is accessed from .Net. However, you may run into problems if your exported functions use C++ objects, and not just plain C data structures.

可以使用PInvoke从未管理的dll调用导出函数。这就是从。net访问非托管Windows API的方式。但是,如果导出的函数使用c++对象,而不只是简单的C数据结构,那么可能会遇到问题。

There also seems to be C++ interop technology that can be of use to you: http://msdn.microsoft.com/en-us/library/2x8kf7zx(v=vs.80).aspx

似乎还有c++的interop技术对您有用:http://msdn.microsoft.com/en-us/library/2x8kf7zx(v=vs.80).aspx

#1


7  

You can start with an ordinary native C++ project (imported from, say, Visual Studio 6.0 from well over a decade ago) and when you build it today, it will link to the current version of the VC runtime.

您可以从一个普通的本地c++项目(从十多年前的Visual Studio 6.0导入)开始,当您今天构建它时,它将链接到当前版本的VC运行时。

Then you can add a single new foo.cpp file to it, but configure that file so it has the /CLR flag enabled. This will cause the compiler to generate IL from that one file, and also link in some extra support that causes the .NET framework to be loaded into the process as it starts up, so it can JIT compile and then execute the IL.

然后您可以添加一个新的foo。cpp文件,但要配置该文件,使其具有/CLR标志。这将导致编译器从一个文件生成IL,并链接一些额外的支持,使. net框架在启动时加载到进程中,这样它就可以JIT编译然后执行IL。

The remainder of the application is still compiled natively as before, and is totally unaffected.

应用程序的其余部分仍然像以前一样本地编译,并且完全不受影响。

The truth is that even a "pure" CLR application is really a hybrid, because the CLR itself is (obviously) native code. A mixed C++/CLI application just extends this by allowing you to add more native code that shares the process with some CLR-hosted code. They co-exist for the lifetime of the process.

事实上,即使是“纯”的CLR应用程序也是一种混合,因为CLR本身(显然)是本地代码。混合的c++ /CLI应用程序允许您添加更多的本地代码,这些代码与一些clr托管的代码共享进程。它们在整个过程*存。

If you make a header foo.h with a declaration:

如果你做一个页眉foo。h和声明:

void bar(int a, int b);

You can freely implement or call this either in your native code or in the foo.cpp CLR code. The compiler/linker combination takes care of everything. There should be no need to do anything special to call into native code from within your CLR code.

您可以在本地代码或foo中*地实现或调用它。cpp CLR代码。编译器/链接器组合负责一切。从CLR代码中调用本地代码不需要做任何特殊的事情。

You may get compile errors about incompatible switches:

您可能会收到关于不兼容开关的编译错误:

  • /ZI - Program database for edit and continue, change it to just Program database
  • /ZI -用于编辑和继续的程序数据库,将其更改为程序数据库
  • /Gm - you need to disable Minimal rebuild
  • /Gm -你需要禁用最小重构
  • /EHsc - C++ exceptions, change it to Yes with SEH Exceptions (/EHa)
  • /EHsc - c++异常,在SEH异常的情况下将其更改为Yes (/EHa)
  • /RTC - Runtime checks, change it to Default
  • /RTC -运行时检查,将其更改为默认值。
  • Precompiled headers - change it to Not Using Precompiled Headers
  • 预编译头-更改为不使用预编译头
  • /GR- - Runtime Type Information - change it to On (/GR)
  • /GR- -运行时类型信息-将其更改为On (/GR)

All these changes only need to be made on your specific /CLR enabled files.

所有这些更改只需要在特定/CLR启用的文件上进行。

#2


1  

As mentioned from Daniel, you can fine-tune your settings on file level. You can also play with '#pragma managed' inside files, but I wouldn't do that without reason.

正如Daniel提到的,您可以在文件级别上微调您的设置。您还可以在内部文件中使用“#pragma managed”,但是我没有理由这样做。

Have in mind, that you can create a complete mixed mode assembly. That means, you can compile your native code unchanged into this file PLUS some C++/CLI wrapper around this code. Finally, you will have the same file as native Dll with all your exported native symbols AND as full-fledged .NET assembly (exposing C++/CLI objects) at the same time!

请记住,您可以创建一个完整的混合模式程序集。这意味着,您可以将未更改的本机代码编译到此文件中,并在此代码周围加上一些c++ /CLI包装器。最后,您将同时拥有与本机Dll相同的文件,其中包含所有导出的本机符号和完整的.NET程序集(暴露c++ /CLI对象)!

That also means, you have only to care about exports as far as native client code outside your file is considered. Your C++/CLI code inside the mixed dll/assembly can access the native data structures using the usual access rules (provided simply by including the header)

这也意味着,只要考虑到文件之外的本机客户端代码,您只需关心导出。混合dll/程序集中的c++ /CLI代码可以使用通常的访问规则(仅通过包含header提供)访问本机数据结构

Because you mentioned it, I did this for some non-trivial native C++ class hierarchy including a fair amount of DirectX code. So, no principal problem here.

因为您提到了它,所以我为一些非平凡的本地c++类层次结构做了这个工作,包括相当数量的DirectX代码。所以,这里没有主要问题。

I would advise against usage of pInvoke in a .NET-driven environment. True, it works. But for anything non-trivial (say more than 10 functions) you are certainly better with an OO approach as provided by C++/CLI. Your C# client developers will be thankful. You have all the .NET stuff like delegates/properties, managed threading and much more at your finger tips in C++/CLI. Starting with VS 2012 with a somewhat usable Intellisense too.

我建议不要在. net驱动的环境中使用pInvoke。真的,它的工作原理。但是对于任何重要的东西(比如超过10个函数),使用c++ /CLI提供的OO方法肯定会更好。您的c#客户开发人员将感激不尽。你拥有所有的。net的东西,比如委托/属性,托管线程,以及更多的在c++ /CLI中的手指技巧。从VS 2012开始,也有一些可用的智能感知。

#3


0  

You can use PInvoke to call exported functions from unmanaged DLLs. This is how unmanaged Windows API is accessed from .Net. However, you may run into problems if your exported functions use C++ objects, and not just plain C data structures.

可以使用PInvoke从未管理的dll调用导出函数。这就是从。net访问非托管Windows API的方式。但是,如果导出的函数使用c++对象,而不只是简单的C数据结构,那么可能会遇到问题。

There also seems to be C++ interop technology that can be of use to you: http://msdn.microsoft.com/en-us/library/2x8kf7zx(v=vs.80).aspx

似乎还有c++的interop技术对您有用:http://msdn.microsoft.com/en-us/library/2x8kf7zx(v=vs.80).aspx