引用加载的本机DLL
本文关键字:DLL 本机 加载 引用 | 更新日期: 2023-09-27 18:03:53
我使用的是用VS2008构建的第三方dll,它依赖于msvcr90.dll
打印到stdout
。我尝试用SetStdHandle
重定向此输出,但dll似乎错过了在返回之前刷新输出缓冲区的最后调用。
仅仅使用
[DllImport("msvcr90.dll")]
导致DllNotFoundException。
为了解决这个问题,我PInvoke fflush()
和__iob_func()
从msvcr90.dll
驻留在我的WinSxS文件夹。我通过设置dll的完整路径来做到这一点(我在第三方dll上使用DependencyWalker获得了路径)。如果我想把我的程序给别人,或者如果msvcr90.dll
被微软更新了,那当然不是很有用。
谁能给我一个提示,如何告诉DllImport使用最新版本的msvcr90.dll
?
谢谢你的回复!
Andreas我的解决方案
在david的帮助下,我想出了下面的解决方案。msvcr90.dll
不是通过WinSxS定位的,而是从加载的模块列表中获取的。
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
namespace siemens.OptiX
{
static unsafe class FlushPrintBuffer
{
struct CFile
{
char* _ptr;
int _cnt;
char* _base;
int _flag;
public int _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
}
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate CFile* iobFuncDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int flushDelegate(CFile* stream);
static iobFuncDelegate myIobFunc;
static flushDelegate myFlush;
static FlushPrintBuffer()
{
ProcessModuleCollection allLoadedModules =
Process.GetCurrentProcess().Modules;
IntPtr aDllHandle = allLoadedModules
.Cast<ProcessModule>()
.Where(p => string.Compare(p.ModuleName, "msvcr90.dll", true) == 0)
.First()
.BaseAddress;
IntPtr aIobFuncPtr = GetProcAddress(aDllHandle, "__iob_func");
myIobFunc = Marshal.GetDelegateForFunctionPointer(
aIobFuncPtr, typeof(iobFuncDelegate)) as iobFuncDelegate;
IntPtr aFlushPtr = GetProcAddress(aDllHandle, "fflush");
myFlush = Marshal.GetDelegateForFunctionPointer(
aFlushPtr, typeof(flushDelegate)) as flushDelegate;
}
static public void flushNow()
{
CFile* aFilePtr = myIobFunc();
int aRes = myFlush(&(aFilePtr[1]));
}
}
}
我想你会发现很难使用DLLImport
链接到正确的运行时。这是因为您的可执行文件将缺少必要的清单,以使WinSxS的魔力工作。
GetProcAddress
获取函数指针。使用Marshal.GetDelegateForFunctionPointer
将函数指针转换为委托。
为了让模块句柄传递给GetProcAddress
,你可以使用GetModuleHandle(@"msvcr90.dll")
,因为你知道这是加载到你的进程。
用p/invoke获取GetProcAddress
和GetModuleHandle
。
似乎调用GetModuleHandle(@"msvcr90.dll")
将不起作用。使用完整路径调用GetModuleHandle
可以工作,但这不是一个真正可行的解决方案。
相反,像这样枚举加载的模块是很容易的:
IntPtr MyGetModuleHandleByPartialName(string ModuleName)
{
foreach (ProcessModule module in Process.GetCurrentProcess().Modules)
if (module.FileName.ToLower().Contains(ModuleName))
return module.BaseAddress;
return IntPtr.Zero;
}
只是出于兴趣,你已经安装了Visual c++运行时使用安装程序?您是说DLL存在并正确安装,而DLL正在失败?
阅读此处获取更多信息: