引用加载的本机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]));
        }
    }
}

引用加载的本机DLL

我想你会发现很难使用DLLImport链接到正确的运行时。这是因为您的可执行文件将缺少必要的清单,以使WinSxS的魔力工作。

我将为需要导入的函数声明一些委托。使用GetProcAddress获取函数指针。使用Marshal.GetDelegateForFunctionPointer将函数指针转换为委托。

为了让模块句柄传递给GetProcAddress,你可以使用GetModuleHandle(@"msvcr90.dll"),因为你知道这是加载到你的进程。

用p/invoke获取GetProcAddressGetModuleHandle


似乎调用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正在失败?

阅读此处获取更多信息: