https://www.cnblogs.com/yeahgis/archive/2011/11/12/2246341.html

环境VS2010

语言:ISO C++、C++\CLI和C# 多语言集成编程

最近在用ASP.NET(C#)开发一个WMS服务器的原型,由于标准C++开发的dll无法直接被C#引用,因此采用(类似SWIG自动包装的效果)C++\CLI进行二次封装和桥接(其实这也是SuperMap的套路,与ESRI的COM的确是不样)。现在遇到这样一个问题,首先做个假设:

(1)最底层的库是标准C++编写,最终生成的DLL假设叫isocpp.dll,这样的dll也叫做native dll,属于unmanaged(非托管)dll。

(2)为了让C#能够调用这个isocpp.dll,我使用C++\CLI对它进行了二次封装,在VS2010中编译时打开CLR支持,生成isocpp_clr.dll。

这样C#就可以直接把这个dll添加到项目的引用里面了,而winForm中只要保证isocpp_clr.dll与isocpp.dll在同一路径下,即可在.net的托管代码中使用isocpp_clr.dll中封装的类和方法,而所有这些类和方法实际是由isocpp.dll进行执行和计算的。因此在桌面程序环境中这样进行桥接是没有任何问题的。

但是换到asp.net的web环境下就产生了很恶心的一个问题:无法加载文件或者程序集isocpp_clr.dll,或者它的某一个依赖项,抛出system.io.filenotfoundexception,注意,此时所有的dll都已经在网站的bin目录下,并且所有dll的相对路径以及各自的绝对路径是没有任何问题的。翻了很多资料,而ASP.NET TEAM对这个问题所给出的解释是:由于asp.net网站在运行时会把所有的文件拷贝到C盘一个临时目录下运行,但是ASP.NET仅会把所依赖的托管dll拷贝过去,比如我的isocpp_clr.dll是可以被自动拷贝过去的,但是万一某个托管dll又依赖于某些非系统的非托管dll时,就会遇到无法加载文件或者程序集,filenotfoundexception这个异常。

明白了怎么回事,要想解决这个问题也并非容易的事情,一开始以为如果DEBUG下不能运行,那么发布出来我把所有的托管还有非托管的dll全都放到bin目录下总行了吧,没想到我又错了,问题依旧。

到这里不得不说国内的网络真的是像一个垃圾填埋场,搜索来搜索去愣是一堆人在那里ctrl c、ctrl  v,真的是太水了,浪费不少时间。最后还是在一个老外的BLOG上找到了解决方法。原文在下面,我是采用2.a办法解决了问题:

(1)对非托管的dll,在对他们进行C++\CLI封装时,在项目的工程属性---连接器--生成事件的POST BUILT SCRIPT中采用命令行调用al.exe进行托管包装,方法:

al.exe /link:"..\bin\a.dll" /out:"..\bin\a_wrp.dll" /platform:x86

al.exe /link:"..\bin\b.dll" /out:"..\bin\b_wrp.dll" /platform:x86

al.exe /link:"..\bin\c.dll" /out:"..\bin\c_wrp.dll" /platform:x86

其他native dll...

(2)这样每个非托管dll会自动生成一个托管的dll,我理解相当于代理,把这个托管dll引入到.net工程的引用中即可保证这些本地的非托管dll可以被拷贝过去。作者说到这里只要把所有的dll都放到网站的bin目录下还不行,还需要为网站的进程设置环境变量。但是作完了这些我在本机debug时网站就能正常运行了,这也让人很费解。

  在托管c++里面设置非托管c++dll延迟导入!

(3)为网站的Process设置临时的环境变量:为网站添加Global类(Global.asax),在application_start中将当前网站的bin目录添加到Process级别的PATH环境变量中,这样就可以保证在任何情况下网站程序(一般是dll)都能找的到托管或者非托管的dll了,我的测试结果也证明了这一点。代码:

protected void Application_Start(object sender, EventArgs e){
    String _path = String.Concat(System.Environment.GetEnvironmentVariable("PATH"), ";", System.AppDomain.CurrentDomain.RelativeSearchPath);
    System.Environment.SetEnvironmentVariable("PATH", _path, EnvironmentVariableTarget.Process);
}

全文转来,备忘也表示对原作者的感谢。

BTW,吐槽一下ms...

链接及原文:http://blogs.msdn.com/b/jorman/archive/2007/08/31/loading-c-assemblies-in-asp-net.aspx

Loading C++ Assemblies in ASP.Net

RATE THIS

Jerry_Orman

31 Aug 2007 4:29 PM

When you reference a Native C++ assembly from ASP.Net you may run into the following error:

System.IO.FileNotFoundException: The specified module could not be found. 
(Exception from HRESULT: 0x8007007E)

[FileNotFoundException: The specified module could not be found. (Exception from HRESULT: 0x8007007E)]
System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection) +0
System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +211
System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +141
System.Reflection.Assembly.Load(String assemblyString) +25
System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +32

[ConfigurationErrorsException: The specified module could not be found. (Exception from HRESULT: 0x8007007E)]
System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +596
System.Web.Configuration.CompilationSection.LoadAllAssembliesFromAppDomainBinDirectory() +3591161
System.Web.Configuration.CompilationSection.LoadAssembly(AssemblyInfo ai) +46
System.Web.Compilation.BuildManager.GetReferencedAssemblies(CompilationSection compConfig) +177
System.Web.Compilation.BuildProvidersCompiler..ctor(VirtualPath configPath, Boolean supportLocalization, String outputAssemblyName) +180
System.Web.Compilation.ApplicationBuildProvider.GetGlobalAsaxBuildResult(Boolean isPrecompiledApp) +3558605
System.Web.Compilation.BuildManager.CompileGlobalAsax() +51
System.Web.Compilation.BuildManager.EnsureTopLevelFilesCompiled() +462

[HttpException (0x80004005): The specified module could not be found. (Exception from HRESULT: 0x8007007E)]
System.Web.Compilation.BuildManager.ReportTopLevelCompilationException() +57
System.Web.Compilation.BuildManager.EnsureTopLevelFilesCompiled() +612
System.Web.Hosting.HostingEnvironment.Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters) +642

[HttpException (0x80004005): The specified module could not be found. (Exception from HRESULT: 0x8007007E)]
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +3539851
System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +69
System.Web.HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr) +252

The core cause to this problem is in the way the operating system loads native DLL's at runtime. Native DLL's are loaded using the following logic which does not include the Temporary ASP.net Files nor the applications /bin folder. This problem will also occur in any .Net application if the Native DLL is not included in the /bin folder with the .EXE file or if the DLL is not in the Path Environment Variable.

  1. The directory from which the application loaded.  In the case of ASP.Net, this will resolve to %windir%\Microsoft.Net\Framework\v###\ or %windir%\system32\inetsrv for IIS 6.
  2. The current directory.  In the case of ASP.Net, this will resolve to %windir%\System32\inetsrv for IIS 6.  If using the built-in web server, this resolves to a path under C:\Program Files\Microsoft Visual Studio 8.
  3. The Windows system directory.  Use the GetSystemDirectory function to get the path of this directory.
  4. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  5. The directories that are listed in the PATH environment variable.

============
The options:
============

  1. Use DLLImport to load the dll using a relative or absolute path at runtime.
  2. Set the PATH Environment Variable so the ASP.Net process can locate the C++ DLL.  You can set this property at runtime so that it only affects the process running your code.  You can also set this globally in the System Properties (Environment Variables | PATH property). Setting this programmatically does not require a reboot and you can point the PATH to the /bin folder of the web app if you want to be able to do XCopy deployments of your ASP.Net application.  Here are the steps to set the Path programmatically from ASP.Net.

Option 2.a - If you want your Native C++ DLL’s loaded from the /bin of the ASP.Net application.

  1. Native C++ DLL project
    1. Use al.exe to build a NativeWrapper for the Native C++ DLL.  This allows you to bring the Native C++ DLL along with the DLL that is referencing it.  You can add this in the Post Build Script of the Native C++ DLL Project to automate this.

      al.exe /link:"$(TargetPath)" /out:"$(TargetDir)$(TargetName).NW.dll" /platform:x86

    2. Managed C++ DLL Project
      1. Reference the NativeWrapper DLL - when you build this project, the native wrapper and Native C++ DLL files are copied to the output directory along with the managed C++ DLL
      2. Set Delay Load DLLs to the Native DLL.  (C++ Project Properties, Expand Linker, select Input, Delay Loaded DLLs) - This prevents the Native DLL from loading when the process starts, giving you a chance to set the PATH Environment variable.  If you don’t set this property, moci.net and its dependencies (i.e. the Native DLL) will be loaded before any of your ASP.Net code can run and this will fail unless you have set the PATH environment variable on the machine level.
    3. ASP.Net Project
      1. Reference the managed C++ DLL - The managed C++ DLL, Native C++ DLL, and NativeWrapper DLL are moved into the applications /bin folder.
      2. Add a Global.asax with the following code.  (Right-click the Web Application, select Add, New Item, select Global Application Class).  You could also use an HTTPModule compiled into a DLL if you don’t want people to be able to change your code.  Application_Start runs one time when the application loads and this code will set the PATH environment variable for the process to include the /bin directory of the application.

        protected void Application_Start(object sender, EventArgs e){
            String _path = String.Concat(System.Environment.GetEnvironmentVariable("PATH"), ";", System.AppDomain.CurrentDomain.RelativeSearchPath);
            System.Environment.SetEnvironmentVariable("PATH", _path, EnvironmentVariableTarget.Process);
        }

Option 2.b - If you want your Native C++ DLLs to load from an installation path outside of the web site you can avoid the AL command.  You would still need to set the Delay Load property on any Managed C++ DLL that loads the Native C++ DLL’s as well as set the Environment Variable.  If you choose to go this route, you can load the path to your Native C++ DLL’s dynamically from the web.config file at runtime:

  1. Native C++ DLL Project - don’t need to do anything in the Post Build Script
  2. Managed C++ DLL Project
    1. Configure Delay Load DLL’s and specify the Native C++ DLL
  3. ASP.Net Project
    1. Reference the Managed C++ DLL - only Managed C++ DLL is in the /bin
    2. In web.config, add the following…use a path where the Native C++ DLL is located:
         <appSettings>
          <add key="NativePath" value="C:\MyNativeDLLs"/>
         </appSettings>
    3. In global.asax, add the following:

      protected void Application_Start(object sender, EventArgs e){
          String _path = String.Concat(System.Environment.GetEnvironmentVariable("PATH"), ";", ConfigurationSettings.AppSettings["NativePath"]);
          System.Environment.SetEnvironmentVariable("PATH", _path, EnvironmentVariableTarget.Process);
      }

2011-11-11 21:22

ASP.NET与非托管DLL的那些事儿【转+增】的更多相关文章

  1. asp.net调用非托管dll,无法加载 DLL,找不到指定模块解决方法。

    最近开发一个项目,里面用到了非.net开发的一个dll文件接口,发现发布到window2003服务器上后,运行网站总是提示 "无法加载 DLL"D:\11\1.dll": ...

  2. 将WinForm程序(含多个非托管Dll)合并成一个exe的方法

    原文:将WinForm程序(含多个非托管Dll)合并成一个exe的方法 开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了. ILMerge能把托管dl ...

  3. 托管DLL和非托管DLL的区别

    首先解释一下,托管DLL和非托管DLL的区别.狭义解释讲,托管DLL就在Dotnet环境生成的DLL文件.非托管DLL不是在Dotnet环 境生成的DLL文件. 托管DLL文件,可以在Dotnet环境 ...

  4. C#调用非托管dll

    以C#开发周立功CAN举例,在官网下载了周立功的demo 一.C++头文件样子 //接口卡类型定义#define VCI_PCI5121 1 //一些结构体定义 typedef struct tagR ...

  5. 托管程序调用非托管dll问题总结

    托管程序Visual Basic.net, 非托管DLL标准C++程序(使用VC++编译) 函数调用定义 第一种写法: <DllImportAttribute("XXX.dll&quo ...

  6. 托管非托管Dll动态调用

    原文:托管非托管Dll动态调用 最近经常看到有人问托管非托管Dll调用的问题.对于动态库的调用其实很简单.网上很多代码都实现了Dll的静态调用方法.我主要谈论下动态库的动态加载. 对于托管动态库,实现 ...

  7. .Net 程序在自定义位置查找托管/非托管 dll 的几种方法

    原文:.Net 程序在自定义位置查找托管/非托管 dll 的几种方法 一.自定义托管 dll 程序集的查找位置 目前(.Net4.7)能用的有2种: #define DEFAULT_IMPLEMENT ...

  8. 关于C#调用非托管DLL,报“内存已损坏的”坑,坑,坑

    因客户需求,与第三方对接,调用非托管DLL,之前正常对接的程序,却总是报“内存已损坏的异常”,程序进程直接死掉,折腾到这个点(2018-05-11 00:26),终于尘埃落定,直接上程序. 之前的程序 ...

  9. C#如何加载嵌入到资源的非托管dll

    如何加载非托管Dll 我们总会遇到需要加载非Win32的非托管dll,这里推荐一种方式就是将那些非win32的非托管dll嵌入资源的方式,在入口解压并且加载的方式,我先来看看如何实现吧,首先我们准备好 ...

随机推荐

  1. CentOS 下运行.net Core程序

    系统: 阿里云的默认 CentOS 7.5 镜像 项目环境:.Net Core 2.2 一.安装.Net Core的运行环境 第一步,如果是一台新的服务器,可以升级一下系统的基础软件.如果没有必要也可 ...

  2. FFMPEG_avi转码到mp4(aac+h264)源码

    #include <ffmpeg/avcodec.h>#include <ffmpeg/avformat.h>#include <stdio.h>#include ...

  3. 如何传递大文件(GB级别)

    一.拆分:压缩工具,压缩并拆分为多个小文件. 二.QQ离线传输 QQ离线文件有限制条件: 1.离线传送的文件,为用户保存7天,逾期接收方不接收文件,系统将自动删除该文件: 2. 离线传送的文件,单个文 ...

  4. jmeter的简单使用0723

    一.添加http请求 1.右击线程组---添加---取样器---http请求,具体内容如下图所示.如果请求带参数,则要点击下方的添加按钮来添加参数 2.查看请求结果,同样右击线程组-添加---监听器- ...

  5. SSH SSL TELNET的比较(转)

    转载链接  https://blog.csdn.net/baidu_39486224/article/details/81295701 SSL(Secure Sockets Layer (SSL) a ...

  6. http,socket,进程通信,网络通信(1)

    众所周知,网络通信本质上就是进程间通信,进程间通信有以下常见的通信方式: 1,管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用,进程的亲缘关系通常指父子进 ...

  7. Linux命令——od

    参考:Linux OD Command Tutorial for Beginners (6 Examples) 简介 查看普通文本文件,可以使用cat.head.tail.tac.less.more等 ...

  8. Docker容器网络篇

    Docker容器网络篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Docker的网络模型概述 如上图所示,Docker有四种网络模型: 封闭式网络(Closed conta ...

  9. Linux必知必会--grep

    花更少的时间,去验证一件事情:你到底是富翁,还是贫民. --一位历经沧桑的炒客 转自:https://man.linuxde.net/grep grep命令 grep(global search re ...

  10. windows10访问ftp中文乱码怎么办?

    windows10访问ftp中文乱码怎么办? 打开控制面板 选择时间和区域 选择更改数字格式 点击管理并点击更改系统区域设置 打勾