我有点困惑,可能这个问题很傻.
为非托管组件分配的内存在哪里?
在我的.net代码中,如果我启动了一个非托管组件,这个组件将被加载并分配内存?
CLR如何在托管堆和非托管堆之间进行调用?
编辑
感谢您的回复,但我要问的是假设我做了一个User32.Dll的DLLIMPORT,这显然是一个非托管的DLL,我现在调用User32.DLL中的一些函数我的问题,CLR如何编组我对这个无人dll的调用?
Han*_*ant 10
它开始很简单.pinvoke marshaller首先调用LoadLibrary并传递您指定的DLL名称DllImportAttribute.Value属性.在您的情况下,user32.dll已经加载,因为它由.NET引导程序加载,它的引用计数只是递增.但通常Windows加载器会将DLL映射到进程的地址空间,以便可以调用导出的函数.
接下来是GetProcAddress以获取要调用的函数的地址,即DllImportAttribute.EntryPoint属性.除非您使用ExactSpelling,否则编组器会进行几次尝试.像"foo"这样的函数名被测试了几种可能的方式,foo和fooW或fooA.令人讨厌的Win32实现细节与Unicode和Ansi字符之间的区别有关.CharSet属性在这里很重要.
现在我需要挥手一点,因为它变得棘手.marshaller构造一个堆栈帧,设置需要传递给导出函数的参数.这需要低级别的代码,小心地从窥探中排除.以它的面值来表示它执行Marshal类支持的托管和非托管类型之间的转换.DllImportAttribute.CallingConvention属性在这里很重要,因为它确定需要放置哪个参数值,以便被调用函数可以正确读取它.
接下来,它设置了一个SEH异常处理程序,以便可以捕获被调用代码引发的硬件异常并将其转换为托管异常.生成更常见的一个,AccessViolationException.和别的.
接下来,它在堆栈上推送一个特殊的cookie,以指示非托管代码即将开始使用堆栈.这可以防止垃圾收集器浮入非托管堆栈帧并将其在那里找到的指针解释为托管对象引用.您可以在调试器的调用堆栈中看到此cookie,[Managed to Native Transition].
接下来,只是间接调用GetProcAddress()中的函数地址.这会使非托管代码运行.
调用之后,可能需要进行清理以释放分配用于传递非托管参数的内存.可能需要将返回值转换回托管值.就是这样,假设没有发生任何令人讨厌的事情,继续执行下一个托管代码语句.