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. 基于RBAC模型的权限设计:如何设计系统权限体系?

    一.什么是RABC RBAC(基于角色的权限控制)模型的核心是在用户和权限之间引入了角色的概念.取消了用户和权限的直接关联,改为通过用户关联角色.角色关联权限的方法来间接地赋予用户权限(如下图),从而 ...

  2. java-Ehcache缓存

    springmvc配置文件: <beans .... xmlns:cache="http://www.springframework.org/schema/cache" xs ...

  3. CSS的一个小bug,Gradient has outdated direction syntax. New syntax is like `to left` instead of `right`.

    在vue重新渲染页面的时候,报了一个错误: 翻译了报错信息后,Gradient has outdated direction syntax. New syntax is like to left in ...

  4. C程序中的内存分布

    一个典型的C程序存储分区包含以下几类: Text段 已初始化数据段 未初始化数据段 栈 堆 进程运行时的典型内存布局 1. Text段 Text段通常也称为代码段,由可执行指令构成,是程序在目标文件或 ...

  5. ant安装(Windows)

    ant安装(Windows) ant 下载之前参考一下官网的ant与java版本依赖 1. 下载地址 2. 解压与配置 1. 下载地址 ant官网 所有版本 2. 解压与配置 java版本:1.8.0 ...

  6. 石子归并(区间dp 模板)

    区间dp入门 #include<iostream> #include<cstdio> #include <cctype> #include<algorithm ...

  7. Kotlin协程第一个示例剖析及Kotlin线程使用技巧

    Kotlin协程第一个示例剖析: 上一次https://www.cnblogs.com/webor2006/p/11712521.html已经对Kotlin中的协程有了理论化的了解了,这次则用代码来直 ...

  8. jq function return value

    所有 JS  函数 都会返回值 假如 没有 return  则返回 undefined

  9. EntityFramework6 学习笔记(二)

    使用EF对数据库进行操作,整个过程就像操作数组一样,我们只管修改或向集合中添加值,最后通知EF保存修改后的结果就可以了. 准备工作 为了演示,我在数据库中建了两张表.class表用于表示班级,clas ...

  10. 题解 UVa11752

    题目大意 输出所有小于 \(2^{64}-1\) 的正整数 \(n\), 使得 \(\exists p, q, a, b\in \mathbb{N+}, p\neq q\rightarrow a^p= ...