.Net中消除Dll中的dependency

本文介绍了解决.NET Class Library项目中dll依赖问题的方法,通过给未签名的控件或dll添加强名称并注册到全局程序集缓存(GAC)中,从而避免在使用自定义dll时携带额外依赖。
  我们在做.Net Class Library项目时常常会遇到这样的问题,我想生成一个dll供其它程序使用,但在我的项目里,又需要引用一些其它的reference,像ActiveX控件或其它dll,而这些控件或dll又没有strong name,不能写入到GAC(Global Assembly Cache)中,因而,在注册使用你的dll时,就必须带上这些引用的控件或dll,才能完成注册。然而,这并不是我们需要的,我们只想提供一个dll给人家用就行了,为什么还要带上一堆的控件或dll呢?别人也不愿意这样。那么,有什么办法解决这个问题呢?

  正好现在做的这个项目就是这种情况,看了一下网上的资料也不多,于是将自己的解决方法share一下,有什么不好的地方,恳请指正。

  大家都知道,在.Net中,如果你试图将一个dll写入到GAC中,那么除了你的dll项目要使用strong name以外,你的项目中用到的其它的控件或dll都需要有strong name,否则,当你注册你的dll时,会提示缺少dependency。这一点让人很烦,但应该有它的好处,利于版本控制。既然是这样,我们只有将引用到的控件或dll都加上strong name,并写入到GAC中,这样在注册你的dll时,就会到GAC中去找它所用到的控件或dll了。那么,如何做呢?大致分两步:

  1、给需要引用的控件或dll加strong name

  这是必须要做的,否则你无法把他们写到GAC中。.Net的SDK提供一个给程序集生成强名的工具,其实不只是生成,还有管理及签名的验证等,只是根据不同的option来的。详细说明请参考MSDN。下面是通过sn创建一个key pair,存储在keyfile.snk中:

%SystemRoot%\Microsoft.NET\Framework\v1.1.4322\sn -k keyfile.snk

  这样就生成了一个密钥对。如果你的项目中没有引用其它的不带强名的控件或dll的话,只是想把自己的dll写入GAC,那么在你项目的AssemblyInfo.cs中,把AssemblyKeyFile加上,就是你刚才生成的keyfile.snk文件。

[assembly: AssemblyKeyFile("..\\..\\keyfile.snk")]

  这里的路径是指编译后项目输出的相对路径,所以,如果这里写成这样的话(当然你也可以修改),就应该把刚才生成的keyfile.snk拷贝到项目的跟目录下,以确保在编译的时候能找到snk文件。这样,编译后的dll就可以写到GAC中了:

%SystemRoot%\Microsoft.NET\Framework\v1.1.4322\gacutil -i yourdll.dll

  如果你的项目中引用了其它的不带有强名的控件或dll的话,就需要再做下一步。

  2、给不带有强名的控件或dll加上强名

  这里要用到两个工具,也是.Net自带的,tlbimp和aximp。tlbimp是将COM类型库中的类型定义转换为CLR程序集的等效定义,aximp是将COM类型库中的类型定义转换为windows窗体控件,详细说明请参考MSDN。
  假设你要给tom.dll和MSFlxGrd.ocx加上强名:

tlbimp ./nostrongname_dll/tom.dll /keyfile:./snk/tom.dll.snk /out:./strongname_dll/Interop_tom.dll

aximp .
/nostrongname_dll/MSFlxGrd.ocx /keyfile:./snk/MSFlxGrd.ocx.snk ./snk/AxMSFlxGrd.ocx.snk

  tlbimp还有很多选项可以用,比如/namespace:Namesapce, /reference:FileName, /publickey:FileName等等,这个可以到.Net Command窗口输入tlbimp回车就可以看到很多帮助。不过我们常用比如/namesapce和/reference。/namesapce可以不加,这时用的是默认的比如上例中的Interop_tom。/reference对我们来说一般比较有用,比如上例中的tom.dll有引用了其它的dll,而我们在给tom.dll加了强名之后又不想把它引用的dll都加进来,这时就要用到/reference选项了。比如tom.dll又引用了tom1.dll和tom2.dll,如果我们不加/reference选项,那么在执行完tlbimp之后,在./strongname_dll目录下除了Interop_tom.dll外,还会将tom1.dll和tom2.dll一起加进来。这样就麻烦了,因为我们在使用Interop_tom.dll的时候还要带着它们,可这不是我们需要的。所以我们可以这样做,假设我们已经将tom1.dll和tom2.dll拷贝到/nostrongname_dll目录下了:

tlbimp ./nostrongname_dll/tom.dll /keyfile:./snk/tom.dll.snk /reference:./nostrongname_dll/tom1.dll /reference:./nostrongname_dll/tom2.dll /namesapce:tom /out:./strongname_dll/Interop_tom.dll

  这样,在./strongname_dll目录下就不会再有tom1.dll和tom2.dll了。不过tom1.dll和tom2.dll也应该是加了强名的才行。

  这里,tom.dll.snk、MSFLlxGrd.ocx.snk和AxMsFlxGrd.ocx.snk是根据第一步产生的,每一个dll都要对应一个snk。tom.dll为转换过的dll的名字,没有什么其它含义。另外需要说明的是MSFlxGrd.ocx会产生两个dll,分别是MSFlexGridLib.dll和AxMSFlexGridLib.dll。个人理解为在窗体初始化时会产生一个AxMSFlexGridLib,不知谁有更好的解释?

  这样就把tom.dll和MSFlxGrd.ocx控件加上了强名称并转换为相应的dll了,再把它们写入到GAC中:

%SystemRoot%\Microsoft.NET\Framework\v1.1.4322\gacutil -i tom.dll
%SystemRoot%\Microsoft.NET\Framework\v1.1.4322\gacutil 
-i MSFlexGridLib.dll
%SystemRoot%\Microsoft.NET\Framework\v1.1.4322\gacutil 
-i AxMSFlexGridLib.dll

  剩下的工作就是将它们重新引用到你的项目中,重新编译,这样生成的dll在注册时就不需要任何dependency了,因为它们已经在GAC中了,打开c:\winnt\assembly即可看到。

  如果要将它们从GAC中删除,则:

%SystemRoot%\Microsoft.NET\Framework\v1.1.4322\gacutil -u tom.dll
%SystemRoot%\Microsoft.NET\Framework\v1.1.4322\gacutil 
-u MSFlexGridLib.dll
%SystemRoot%\Microsoft.NET\Framework\v1.1.4322\gacutil 
-u AxMSFlexGridLib.dll

  tom、MSFlexGrid和AxMSFlexGrid为GAC中的名字,这里不需要加任何路径。
<think>我们正在处理一个复杂的问题:使用VS2010编译VC++6.0程序时出现0xc000007b错误,并且Dependency Walker工具无响应。我们需要结合用户的问题描述和提供的引用内容来提供解决方案。 问题分析: 1. 错误代码0xc000007b通常表示应用程序无法启动,常见原因包括: - 32位/64位不匹配(例如,32位程序加载了64位DLL或反之) - 系统DLL缺失或损坏(如MSVCRT、MFC相关DLL) - 依赖的运行时库(如VC++运行库)未正确安装或版本冲突 2. Dependency Walker无响应:可能是由于分析大型项目或复杂依赖关系导致,也可能是因为路径中包含中文字符或特殊字符。 解决方案步骤: 步骤1:确认平台目标(32位/64位) - 在VS2010中,打开项目,进入“生成”菜单 -> “配置管理器”。 - 确保“活动解决方案平台”为Win32(即32位)。如果不存在,则新建一个Win32平台。 - 重新编译项目,确保生成的是32位可执行文件。 步骤2:修复Dependency Walker无响应问题 - 将生成的exe文件复制到一个简单的英文路径下(例如C:\test\),然后使用Dependency Walker打开。避免中文字符或长路径。 - 如果Dependency Walker仍然无响应,可以尝试使用其他工具(如微软的Sysinternals Suite中的Process Monitor)来监控程序启动时的文件访问情况,查找缺失的DLL。 步骤3:检查并安装VC++运行库 - VS2010编译的程序默认依赖VC++2010运行库(msvcr100.dll, msvcp100.dll等)。如果目标机器没有安装,则会出现0xc000007b错误。 - 解决方案: a. 在开发机上,找到VS2010安装目录下的redist文件夹(例如:C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\redist\x86\Microsoft.VC100.CRT),将里面的DLL复制到应用程序同一目录。 b. 或者下载并安装VC++2010运行库可再发行组件包(vcredist_x86.exe)[^2]。 步骤4:检查项目设置中的运行时库选项 - 在VS2010中,右键项目 -> 属性 -> 配置属性 -> C/C++ -> 代码生成 -> 运行时库。 - 对于Debug版本,选择“多线程调试(/MTd)”;对于Release版本,选择“多线程(/MT)”。这样可以将运行时库静态链接到可执行文件中,避免依赖外部DLL。 步骤5:检查并修复系统文件 - 使用系统文件检查器(sfc /scannow)扫描和修复损坏的系统文件。 - 确保DirectX正常工作,因为0xc000007b错误也可能是DirectX组件问题。下载并运行DirectX修复工具(增强版)[^2]。 步骤6:检查其他依赖项 - 如果项目使用了MFC,确保在项目属性中设置了正确的MFC使用方式(静态链接或动态链接)。建议使用静态链接(在“配置属性”->“常规”->“MFC的使用”中选择“在静态库中使用MFC”)。 - 如果项目使用了ATL或其他库,同样检查相关设置。 步骤7:使用Process Monitor工具监控 - 下载Process Monitor(微软Sysinternals工具之一)。 - 运行该工具,设置过滤器为进程名(即你的exe文件名),然后启动你的程序。观察程序启动时访问的文件,特别是那些返回“NAME NOT FOUND”或“ACCESS DENIED”的DLL,这些就是缺失或权限不足的文件。 步骤8:兼容性设置 - 右键点击生成的exe文件,选择“属性”->“兼容性”选项卡,勾选“以兼容模式运行这个程序”,选择“Windows XP (Service Pack 3)”,并勾选“以管理员身份运行此程序”。 步骤9:清理和重建 - 在VS2010中,执行“清理解决方案”,然后重新生成。 步骤10:检查代码兼容性 - VC++6.0和VS2010之间存在一些语法和库函数的差异。检查代码中是否有过时的函数(如strcpy建议改为strcpy_s等)或宏定义差异。在编译过程中,注意警告信息,尽可能修复所有警告。 如果以上步骤仍不能解决问题,考虑将项目升级到更高版本的Visual Studio(如VS2019),但升级过程也可能遇到兼容性问题,需要逐步调整。 预防措施: - 在迁移旧项目时,建议在VS2010中创建新项目,然后添加原有源文件,而不是直接打开vc6的dsp文件。 - 使用版本控制系统(如Git)管理代码,便于回退和比较。 相关问题: §§相关问题§§ 1. 如何将VC++6.0项目迁移到VS2019并避免兼容性问题? 2. 如何解决Dependency Walker分析大型程序时无响应的问题? 3. 如何排查和修复Windows应用程序的0xc000007b错误?</think>### 解决VS2010编译VC++6.0程序出现0xc000007b错误且Dependency Walker无响应的问题 #### 问题分析 错误代码0xc000007b通常表示**应用程序无法加载依赖项**,主要原因包括: 1. **32位/64位冲突**:VS2010默认可能生成64位程序,而VC++6.0项目是32位[^1] 2. **运行时库缺失**:VS2010依赖MSVCRT100.dll等新库,VC++6.0使用旧版MSVCRT.dll 3. **Dependency Walker无响应**:复杂依赖链或路径问题导致卡死 4. **兼容性设置错误**:未正确处理旧版API或库文件 --- ### 解决方案(分步操作) #### 步骤1:强制32位编译(关键) 1. 在VS2010中打开项目 2. 转到 **生成 → 配置管理器** 3. 创建新平台: - 点击 **活动解决方案平台 → 新建** - 选择 **x86**(32位),复制设置从"Win32" 4. 重新编译项目 *此步解决90%的0xc000007b错误[^1]* #### 步骤2:绕过Dependency Walker的替代方案 当Dependency Walker无响应时,改用以下工具: 1. **Process Monitor**(微软官方工具): - 下载地址:https://docs.microsoft.com/zh-cn/sysinternals/downloads/procmon - 过滤设置: ```filter Process Name: 你的程序名.exe Result: NAME NOT FOUND ``` - 检查红色条目,定位缺失的DLL 2. **VS自带模块列表**: - 在VS2010中:**调试 → 窗口 → 模块** - 运行程序时查看加载失败的DLL(标记为"未加载") #### 步骤3:修复运行时库依赖 1. **静态链接运行时库**: - 项目属性 → C/C++ → 代码生成 → 运行时库 - Debug模式:选择 **/MTd** - Release模式:选择 **/MT** *消除对MSVCRTxxx.dll的依赖[^2]* 2. **手动部署DLL**: - 从VS2010安装目录复制: ``` C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\redist\x86\Microsoft.VC100.CRT\ ``` - 将`msvcr100.dll`, `msvcp100.dll`等放入exe同级目录 #### 步骤4:处理VC++6.0特有依赖 1. **MFC库处理**: - 项目属性 → 常规 → MFC的使用 → 选择 **在静态库中使用MFC** - 或复制MFC100.dll到程序目录 2. **兼容性修补**: - 对旧版API添加适配代码: ```cpp #if _MSC_VER >= 1600 // VS2010版本号 #define _CRT_SECURE_NO_WARNINGS #pragma comment(lib, "legacy_stdio_definitions.lib") #endif ``` #### 步骤5:系统级修复 1. **运行库安装**: - 下载并安装 **vcredist_x86.exe** (VS2010版): [官方下载链接](https://www.microsoft.com/zh-CN/download/details.aspx?id=5555) 2. **DirectX修复**: - 使用工具修复d3dx9等组件: [DirectX修复工具增强版](https://blog.csdn.net/vbcom/article/details/6962388) 3. **注册表清理**: - 运行`regedit` → 删除残留项: ``` HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{旧版VC++ GUID} ``` --- ### 预防措施 1. **项目迁移规范**: ```mermaid graph LR A[VC++6.0项目] --> B(新建VS2010空项目) B --> C[手动添加.h/.cpp文件] C --> D[设置平台工具集为v100] D --> E[逐步替换废弃API] ``` 2. **依赖管理**: - 使用**NuGet**添加库:工具 → NuGet包管理器 → 安装`Microsoft.VisualCpp.2010.Redist-x86` - 设置环境变量`PATH`包含所有自定义DLL路径 3. **版本控制建议**: - 在`.gitignore`中添加: ``` # 忽略本地DLL副本 *.dll !redist/*.dll # 保留redist目录 ``` > **关键提示**:对于复杂遗留项目,建议在虚拟机中保留VC++6.0环境用于最终编译,同时用VS2010进行渐进式迁移[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值