上学期帮SF做项目,写个可视化大开口板应力集中系数和应力集中点位置的程序。要求计算部分必须用C++或者Fortran来写,方便SF继续开发,但又为了写图形界面的时候图省事,最后决定算法部分用C++来写,编译成dll让C#来调用。
把dll文件放在C#项目的..\bin\Debug目录下,C#项目在自己的电脑上一直工作得很正常;单独把exe和dll文件放在同一个目录下,exe也能正常运行。但是把这个两个文件拷到其他的电脑里运行发现在一部分电脑里会出现异常:在尚未调用dll的时候C#编写的exe可以正常运行,当需要调用自己编写的dll时,就会报错,无法加载dll,找不到指定的模块(异常来自HRESULT:0x8007007E)。
为了解决这个问题真是经历了千辛万苦的尝试,真想抱着电脑大哭一场。
尝试一:把dll文件拷贝到目标电脑的C:\Windows\System32目录和系统的dll放在一起,发现问题不在这里。exe最先寻找dll的位置就是当前目录,然后才是Windows系统目录和PATH环境变量列出的位置。
尝试二:尝试不同的release版本。出现异常的两台目标电脑都是32位系统,所以release了32位版本放到目标电脑上,可是异常照旧。直到在一台64位机器上也出现同样的异常,放弃了这个尝试。
此时遇到一个转折点,在目标电脑上安装了VS 2010后,发现异常解决了!这为我们寻找这个异常的根本原因提供了很大的帮助。
尝试三:目标电脑的.net Framework版本低于我们编写的C#项目使用的.net Framework版本。win 7系统自带.net Framework 3.5,而安装VS2010同时为电脑安装了.net Framework 4.0,会不会是因为我在项目的属性里目标框架选择了.net框架4.0呢?转念一想,如果是这样的话,那应该是C#可执行程序一开始运行就出现异常吧!为了调用非托管dll,using了一个命名空间System.Runtime.InteropServices,它调用了mscorlib.dll,这个是.net的核心运行库Common Language Runtime Library,2.0里就有,3.5完全可以向下兼容。可以尝试下把目标框架改成.net 3.5重新release看看能不能在出问题的目标电脑上运行,也可以排除这个原因。在csdn上看到了给目标电脑安装了.net 4.0也无济于事的小伙伴,所以抛弃这个可能性。
尝试四:这个也是我最终认定的异常的根本原因。我把视线从C#转回dll,突然想起来,这个dll也是我用VS 2010编译的呀!这个家伙编译的东西在其他电脑不能正常工作简直太正常了。不同版本的系统对dll的调用应该没有什么差异,问题很可能出在不同系统所具备的开发环境不同。这个时候就要看一看我们用VS 2010都调用了什么dll。VS 2010里没有自带的depends工具,于是在dependencywalker.com下了一个。
可以看到用VS 2010编译出的dll调用了一个叫做MSVCR100D的动态链接库。这是VS 2010中一个重要的动态链接库。
在出现异常的电脑上运行depends工具,我们发现果然是缺少了MSVCR100D.DLL!
于是我们就找到了异常0x8007007E出现的根本原因!目标机器中缺少我自己编写的dll调用的dll!
我们继续尝试如何方便快速的解决这个问题。
注意到MSVCR100D.DLL的文件名以D结尾,说明这是一个在debug时才会调用的动态链接库,不在Microsoft Visual C++ 2010 Redistributable Package里面。不妨release一个dll来试一下。或者仍然使用debug模式,在项目属性Runtime Lib里把MDd(Multi-threaded Debug DLL)改成MD,应该就不会调用这个dll了。这些方法我都没有尝试,像我一样暴力的给目标电脑装一个VS 2010也是一种解决办法。当然把这个dll放在目标电脑里也可能会解决这个异常,只是我没有再做尝试了。
在解决这个异常的过程中,发现能引起这个异常的原因有很多。尤其是我们在使用别人编写的dll文件的时候,这个文件很可能调用了其他我们不知道的其他dll,最好用depends工具事前分析一下。原因往往是目标电脑上缺少了一些运行这个可执行文件的支持,也许是.net框架,也许是dll文件。对症下药,给出现异常的电脑安装相应的.net框架,或者编译环境的运行库,再或者把缺少的dll拷贝到本地,算是出现这个异常时我们的几个思路。如果是自己写的dll,也不要忽略我们写的dll本身的问题。