一般而言,隐式加载如果加载出错的话,系统都会给予提示。例如 aaa.Exe隐式加载了bbb.dll, 而bbb.dll同样隐式加载了ccc.dll,如果ccc.dll在搜索路径上不能找到,那么运行aaa.Exe, 加载bbb.dll就会失败,系统会给予提示:
---------------------------
aaa.exe - 无法找到 DLL
--------------------------
无法找到动态链接库 ccc.dll 于指定的路径 C:\WINNT\system32;C:\WINNT\system;C:\WINNT; 上。 
---------------------------
确定   
---------------------------而如果aaa.Exe显式加载了bbb.dll呢?那么,LoadLibrary 就会失败,使用GetLastError,得到错误代码126--找不到指定的模块,却无法获得如上的加载失败原因。这就让人一时摸不着头脑了....我的问题就是:如何在显式加载失败时,使之类似隐式加载一般,报告出加载失败的具体原因?解决此问题也许只是一个API,也许是一大段代码,总之,烦请指教。

解决方案 »

  1.   

    请用顶层异常处理SetUnhandledExceptionFilter,可以获取错误。
    在UnhandledExceptionFilter,系统会给你现场和详细的信息。
      

  2.   

    http://www.vckbase.com/code/downcode.asp?id=2495
      

  3.   

    使用DelayLoad技术。MSDN里有篇文章,你找找看。给你个例子:#pragma comment( lib, "DELAYIMP.LIB" )#pragma comment(linker, "/DELAYLOAD:DelayLoadDLL.dll")
    #pragma comment(linker, "/DELAY:nobind ")
    #pragma comment(linker, "/DELAY:unload ")#pragma comment( lib, "..\\DelayLoadDLL\\Release\\DelayLoadDLL.lib" )//这个是dll的库
    extern void foo();/////这个是需要调用的函数__try 
    {
    foo();
    __FUnloadDelayLoadedDLL("DelayLoadDLL.dll");
    }
    __except (DelayLoadDllExceptionFilter(GetExceptionInformation()))
    {
    }LONG WINAPI DelayLoadDllExceptionFilter(PEXCEPTION_POINTERS pep) 
    {
    LONG lDisposition = EXCEPTION_EXECUTE_HANDLER;  

    PDelayLoadInfo pdli = PDelayLoadInfo(pep->ExceptionRecord
    ->ExceptionInformation[0]);

    char sz[500] = { 0 };

    switch (pep->ExceptionRecord->ExceptionCode) 
    {
    case VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND):
    wsprintf(sz, "Dll not found: %s", pdli->szDll); 
    break;

    case VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND):
    if (pdli->dlp.fImportByName) 
    {
    wsprintf(sz, "Function %s was not found in %s",
    pdli->dlp.szProcName, pdli->szDll);

    else 
    {
    wsprintf(sz, "Function ordinal %d was not found in %s",
    pdli->dlp.dwOrdinal, pdli->szDll);
    }
    break; 
    default:
    lDisposition = EXCEPTION_CONTINUE_SEARCH;                                                
    break;
    }

    if (lDisposition == EXCEPTION_EXECUTE_HANDLER)
    {
    MessageBox(NULL, sz, NULL, MB_OK);
    }
    return(lDisposition);
    }
      

  4.   

    其实GetLastError已经告诉你原因,只不过是具体的现实需要自己去组织:首先LoadLibrary知道当前要载入哪个dll,其次,可以从系统变量中得到dll的载入路径,两者相加就是隐式连接时的系统提示
      

  5.   

    Sorry, 下午发完贴就直接出去办事去了,晚上又看电视,现在才有空来看看。看了楼上诸位的答案,我感觉还是没发现思路......wangk(倒之): 使用SetUnhandledExceptionFilter 和 UnhandledExceptionFilter 处理,我之前在工程中用过,当时用于致命错误的捕捉,它替代系统的弹出的致命对话框条,记录崩溃现场的日志,虽然实用,但感觉并不适合此场合,LoadLibrary的错误 并不会导致 此类错误发生,这里难道要手动抛出错误?idAnts(Coil & Nova Since 1985) :使用延迟调用DLL动态库首要条件就是此动态库为一个隐式加载的动态库,可偶的库是显式加载,且执行LoadLibrary即失败。此时如何使用上延迟调用技术?况且我们使用的动态库,有不少是第三方,即非本人编写的动态库,要那些库都实现延迟加载编译的话,并不现实啊......flyelf(空谷清音[MVP]): GetLastError 返回的代码是126,既是 "找不到指定的模块" 错误,
    LoadLibrary虽然知道加载的动态库 bbb.dll, 甚至连路径都清清楚楚,可是 bbb.dll 依赖的动态库 ccc.dll不存在,所以说显式一加载bbb.dll 就失败,那么如何让我得到是哪个 ccc.dll不存在呢?实际上隐式加载非常常见,我们基于MFC编写的动态库都是隐式加载了MFC42, MFC71等的动态库,而实际加载这些动态库时如果没有相关隐式链接的那些动态库,loadLibrary就会出错, 此时如何
    让我自己代码获得此类错误呢?盼楼上兄弟继续关注,期待找到答案。
      

  6.   

    GetLastError应该是终极方法了,你试下把dll都放到windows的系统目录再运行
      

  7.   

    Load出错后:
    1.判断该DLL是否存在
    2.读取Dll的隐式加载需要的文件(PE格式分析)
    3.SearchPath在当前文件夹和系统文件夹查找Dll的隐式加载需要的文件是否存在。
      

  8.   

    wangk(倒之): 
       汗,如果真的需要象2一般,"读取dll的隐式加载需要的文件"的话,那么恐怕还要考虑递归---因为如果此dll隐式加载需要的dll可能也隐式加载了一些dll, 更何况如果将任意文件改名为那个需要的文件,你的方法也不适用--查找文件是能够找到的,而LoadLibrary仍然会报错,而且如果以上两点交给系统帮你做--既是不采取显式加载而是隐式加载,系统均能准确的将错误结论得出,所以说仍然没有找到思路呢......
      

  9.   

    LookSail(老得牙都掉了还在学)
      GetLastError的提示非常之不足,以至于此类问题如果是显式加载获得的错误提示信息之少,让人浑摸不着头脑,如果这是终极提示,那么就有问题了。
      我刚才写完贴,随便测试一下,分别采取三个方法来试验:
    1-删去隐式加载库 
       GetLastError报告:找不到指定的模块。
       隐式同帖子正文。
    2-将一个其他的动态库改名成此隐式库
       GetLastError报告 127:找不到指定的程序。 (汗)
       隐式报告:
    ---------------------------
    aaa.exe - 无法找到入口
    ---------------------------
    无法定位程序输入点 func1 于动态链接库 ccc.dll 上。 
    ---------------------------
    确定   
    ---------------------------
    3.随便拷贝一个文本文件改名成此隐式文件。
       GetLastError报告193:%1 不是合法的 Win32 应用程序。
       
      隐式加载报告---------------------------
    aaa.exe - 损坏的图像
    ---------------------------
    应用程序或 DLL C:\Test\Debug\ccc.dll 为无效的 Windows 映像。请再检测一遍您的安装盘。 
    ---------------------------
    确定   
    ---------------------------可诊断性,两下相较,一目了然。
      

  10.   

    1.肯定要用递归,就像Depands工具一样。
    2.如果3用LoadLibrary判断呢?,如果任意文件改名为那个需要的文件还是能知道不能加载成功。
      

  11.   

    2.如果不想用LoadLibrary,其实可以用PE文件分析,PE格式里有记录可执行的类型、入口等……
      

  12.   

    wangk(倒之): 
      之前忙事,再加之再想其他方法,故而没有回答你,你的方法不能说行不通,但是用这种“交通基本靠走,娱乐基本靠手”的方法未免过于繁琐,等这段东西出来,那么倒之版的Depands 也出来了,其实只是需要获知系统信息而已,恐怕还有其他方法,我再想想了......,如果有新的想法,请提示。
      

  13.   

    关注。
    我原来以为是因为采用隐式加载dll时会将所有这个dll与之相关的dll一起加入导出表,但是看来似乎不是(使用Depends看)
      

  14.   

    to winthegame(120斤重的大青蛙) 
       好像没有什么好的方法,你总不能让咱村前的小土路跑宝马之流的车子吧。交通不靠走是不成啦。只能请MS修路了……
      

  15.   

    向来不喜欢拖问题,只不过感觉的确没有找到更好的方法,其实使用LoadLibrary时弹出系统错误框的方法很简单,就是SetErrorMode而已,但要把那个系统框的描述获得到程序中似乎还是没有什么好办法,什么都自己做倒是能做--但总觉得不是好办法,一定还有更好的法子....,算了吧,实在没有太多空多想了,谢谢各位参与,结贴!