包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

情景如下:我有一个项目甲在D盘,里面有一个类库 AbsDataCache,里面有3个cs文件,其中 CacheManager是用来封装 asp.net的cache缓存,以及封装MemcachedCacheProviders缓存的,由于MemcachedCacheProviders已经是封装好的dll文件,所以当我自己把类库AbsDataCache封装成AbsDataCache.dll的时候,出了很多问题

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

1:问题一,如何在 AbsDataCache项目中,引用 MemcachedCacheProviders的dll了?MemcachedCacheProviders的dll放在哪里比较好了?

如果我们将MemcachedCacheProviders的dll,放在了桌面,例如

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

然后,我们去AbsDataCache项目中引用,

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

可以看到我们已经引用成功,查看引用的dll文件会看到路径是在桌面,但是由于  vs默认会把 复制本地设置为true,那么在编译的时候,会将桌面的文件,保存到 bin文件夹下面。我们在项目上点击 重新生成

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

就能看到 bin的 debug文件夹下,已经有引用进来的dll文件了

 包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

我们可以去项目的描述文件看看,会发现里面有几个引用,引用的是桌面上的几个dll文件,这是告诉编译器,当编译的时候,要记得把桌面的文件,拷贝过来(如果复制本地设置为true)

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

(小插曲:可以略过:

其实这样是非常不好的,如果你代码里面有错误,这个时候你编译就会报错,报错之后bin下面的debug文件夹下的所有文件都会删除,假如这个时候你桌面的文件被你删除了,你就把你需要的dll文件都弄丢失了)例如,我估计修改,报错

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

再看看bin下面的debug,全部都没了。

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

接着刚才的,我们看到 bin的 debug文件夹下,已经有引用进来的dll文件了,然后我们拷走,拷贝到一个新的需要使用的项目乙中(在J盘),假如是放在项目下的  “第三方控件”文件夹

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

然后我们在这个新的项目乙上,引用 AbsDataCache这个封装好的dll,(这个时候还有个问题,其他的3个 dll 文件要不要引用呢?)

如果我们只引用 AbsDataCache.dll,会不会报错了?因为如果我们要实现分布式缓存, 这必须是要使用下面的3个dll的,这里我只引用一个,试试看

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

对项目编译一下包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

  发现,所有的文件都过来了,这是为什么了?很奇怪是不是?

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

ok,继续,我们对项目乙里面的代码进行调试一下,

我在页面调用 抽象类的地方,打了一个断点,由于我们拷贝过来的是dll文件(我删除了pdb文件,不可能让你调试进代码),所以应该是跳转到 元数据才对。但是这里居然会跑到D盘的项目甲里面的代码

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

这显然不是我们想要的结果,而且,为什么会这样了?为什么在项目乙里面调试,居然跑到项目甲里面的源代码里面进行了调试?

猜想1:难道是因为我们应用的 AbsDataCache.dll 会去引用源头项目甲里面的代码?那么我们就去甲里面,把刚才的dll的源头,给删掉

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

再来看看 项目乙会怎么样?会不会报错?再次调试,还会去项目甲么?

答案是:我们重新对项目乙进行编译,没报错,bin下面的文件也都还是存在,那么调试了?还会进项目甲么?狗血的很,还是会去项目甲的代码

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

猜想2:我们把项目甲的代码的文件夹给修改掉名字,这样项目乙肯定进不去项目甲进行调试了。

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...  

然后再去项目乙里面试试,这次调试,还能进去项目甲的代码?

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

这次,就进不去了,代码一闪而过,如果我们想看看代码的话,编译器会跳转到元数据(凡事封装好了的dll数据都是元数据,你看不到具体的代码,只有方法,没有方法体,例如我们查看.net自带的类型,方法都是元数据)

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

答案2:修改项目甲里面的文件夹名称,确实是可以防止项目乙进入项目甲,但是这样也未免太无语了吧,不可能每次封装完一个dll,之前的项目就得*改名字吧?

我自己找到的一个解决方法

我们还是先去把项目甲恢复到最开始的状态,名字修改回来,并且准备引用 Memcache的缓存dll文件,这个时候,我们做一点修改

引用的时候,还是引用桌面的文件夹里面的 dll 文件,但是我们在 vs里面,把 Enyim.Caching.dll,log4net.dll和MemcachedProviders.dll的 复制本地属性,修改为false

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

然后我们对项目甲进行编译,这个时候的bin文件夹如下,结果就只有  AbsDataCache.dll文件,其他的3个dll都没有了,当然,这是肯定的,因为我们没有复制过来嘛。

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

然后,我们去项目乙,清除掉以前的所有的引用,删除掉原来引用过来的dll,只复制项目甲里面的 AbsDataCache.dll 文件到 项目乙里面的  “第三方类库” 文件夹,然后在项目乙上,引用

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

我们对项目乙进行重新生成

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

居然还是不报错,但是这个时候,我们的项目乙的bin目录下,只有下面的几个文件,而没有分布式缓存需要的dll

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

虽然编译不报错,但是我们运行呢?那么我们调试一下?

好狗血,居然调试又跑到项目甲的代码里面去了

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

但是接着往下走,就会发现报错了

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

提示 分布式缓存需要的dll文件不存在。(假如你这个时候把桌面的3个dll,拷贝到项目乙的第三方类库文件夹,然后项目乙全部引用,是不会报错的,但是还是一样调试进入项目甲的代码,这个我就不演示了)

 

总结问题就是:为什么项目甲生成的dll文件,被项目乙使用,然后在项目乙里面调试的时候,为什么又会跳转回到项目甲的代码里面?如果这个时候项目甲里面的代码被修改了了?那项目乙岂不是也跟着改变了?

终极回答

在项目甲生成的时候,不管我们是选择debug模式,还是Release模式,实际上都还是生成了对应 pdb文件,这个pdb文件,就是专门帮助调试使用的。每个生成的dll或者是exe,他们对应的pdb名字都是一样的,并且,如果是在允许生成pdb文件的情况下(例如我上面演示的情况下,都是生成了pdb调试文件,实际我们可以在Release模式下,关闭掉PDB文件),每个dll或者是exe,都会在他封装好的头文件里面保留一个对应的PDB文件的GUID码和PDB文件地址(例如项目甲里面生成的dll 对应的地址就是 D:/XXX项目/AbsDataCache/bin/release/XX.pdb)。

这样,当编辑器在碰到项目需要调试的时候,会先去看看你项目里面有没有对应的pdb文件,如果没有,那么就会按照dll里面的头文件里面的PDB文件地址去找PDB文件,这也就是为什么我们项目乙调试的时候,会跑到项目甲的D盘里面去的原因,因为我们拷贝过来的DLL的头文件,包含了 对应的PDB的地址,所以他会找过去。

编辑器寻找PDB的路径是,它通常会从可执行文件或者DLL文件的相同目录中加载pdb符号文件。这正是调试器寻找PDB文件的第一选择。

如果在模块文件的相同目录下找不到匹配的PDB文件,会发生什么呢?我们在前文知道编译器在PE文件中硬编码了一个路径(比如:D:/XXX项目/AbsDataCache/bin/release/XX.pdb),这个路径就是调试器的第二个选择。对于对外发布的应用,很可能这两个路径下都找不到PDB文件。此时调试器会在本地的符号服务器缓存路径下寻找PDB文件。如果本地的符号服务器缓存路径下仍然找不到,它会调试器本身配置的符号服务器中寻找符号文件。如果都找不到(例如我们修改了项目甲的文件夹名称,这样就找不到了),那么VS2010就不调试这段代码了,直接运行过去。下图是VS2010配置符号服务器和本地符号缓存路径的界面。

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

如果这个时候项目甲里面的代码被修改了了?那项目乙岂不是也跟着改变了

答案是,不会。而且如果你真的去项目甲里面修改代码的话,如果项目乙正在调试,而你却想修改项目甲的文件,这个时候编辑器会在项目甲报错:创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件(因为我们的项目甲的调试文件,正在被项目乙调试中)

那,如果是项目甲先修改,然后项目乙再调试呢?这个时候会怎么样?这个时候项目乙的编辑器会报错:源文件与模块生成时的文件不同,仍要让调试器使用它吗?这是因为项目乙的DLL中,记录下他引用的PDB对应有一个GUID码。而项目甲此刻更新了代码,那么新生成的PDB文件的GUID玛就不一样了。

 

实际上,如果是在同一台电脑上,这样调试是没有任何问题的,项目乙调试,跑到项目甲的代码中,也没有啥。相反还能更好的看清代码,只是我第一次遇到的时候,大吃一惊而已,觉得甚至会甲乙互相影响。

为了避免你以后修改了项目甲的代码,而乙还是跑过去调试的话,肯定是不对的。所以我们在项目甲生成的时候,选择 Release 版本,并且,不允许生成 PDB文件

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件...

然后新生成的就应该只有DLL文件了,这个时候项目乙中调试代码就不会跑到项目甲里面去了。

包含别人的dll,然后我们用类库再次封装成dll的时候的注意事项;源文件与模块生成时的文件不同;创建调试信息文件 ··PDB时发生意外的错误,进程无法访问文件,因为另一个程序正在使用此文件... 

全部拷贝,拿到项目乙的 “第三方组件”文件夹,这次再次引用,就不会跳转到项目甲的代码去了。

 

关于可以生产PDB的情况下,DLL会包含PDB信息(例如会包含GUID和PDB的地址),可以看看这篇文章

http://www.cnblogs.com/xuanhun/archive/2011/10/11/2207398.html

转载于:https://www.cnblogs.com/joeylee/archive/2012/12/12/2815210.html