2

My program loads several dlls and calls their functions. The dlls can use different versions of CRT.

When C runtime checks the validity of arguments and finds problems, it calls the invalid parameter handle, which in turn, closes the application, with or without the "Send-Don't send" dialog.

I tried calling *_set_invalid_parameter_handler* but it only works if it is called from within the bad dll. I tried SetErrorMode, but all I managed to do is get the process killed without the dialog.

Is there any way to handle those exceptions? I don't care if some resources are compromised. All I want is to allow users to save the configuration. If the dialog appears, they click on it and kill the process.


EDIT It turns out the solution to load all versions of CRT or to enumerate all DLLs fails. To make all clear, here is a small example to play with:

This would be my main application (let's call the file application.c):

#include <windows.h>

void myInvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved) {
   wprintf(L"Invalid parameter detected in function %s. File: %s Line: %d\n", function, file, line);
   wprintf(L"Expression: %s\n", expression);
}

void fixMyProblem() {
}

int main(int argc, char **argv) {
    HMODULE hModule = LoadLibrary("extension.dll");
    void (WINAPI *function)() = GetProcAddress(hModule, "function");
    fixMyProblem();
    function();
}

This application loads a dll that does bad things (it is not developed by me, so I will not accept any solution telling me to fix the bugs there). Lets' call that file extension.c.

#include <stdio.h>

__declspec(dllexport) void function() {
    printf("do bad stuff");
    fopen(NULL, "r");
}

To compile, do:

cl extension.c /link /OUT:extension.dll /DLL
cl application.c

The question is what do I do in function fixMyProblem(), so that I don't get the send/don't send dialog on XP or the application has stopped working dialog on 7.

According to David Gladfelter I should do

void fixMyProblem() {
    _set_invalid_parameter_handler(myInvalidParameterHandler);
}

and also do this for each version CRT available. It turns out that even with one single version of CRT (I use the same for both exe and dll), it still does not work. They both use the same version of CRT, but is seems they do not use the same CRT.

If this is is the case, I assume that the stuff I have to change is inside the DLL. Of course, it does not export *_set_invalid_parameter_handler*.

But to be fair to David Heffernan, here is the implementation for his solution:

#include <Psapi.h>
#pragma comment(lib, "Psapi.lib")
void fixMyProblem() {
    HANDLE hProcess = GetCurrentProcess();
    HMODULE *hModules;
    DWORD requiredSize = 0;
    DWORD secondRequiredSize = 0;
    if (!EnumProcessModules(hProcess, NULL, 0, &requiredSize)) {
        printf("oops\n");
        return;
    }
    hModules = malloc(requiredSize);
    if (EnumProcessModules(hProcess, hModules, requiredSize, &secondRequiredSize)) {
        int i;
        int loadedModules = min(requiredSize, secondRequiredSize) / sizeof(HMODULE);
        for (i = 0; i < loadedModules; i++) {
            void *(WINAPI *_set_invalid_parameter_handler_function)(void *) = (void *(WINAPI *)(void *)) GetProcAddress(hModules[i], "_set_invalid_parameter_handler");
            if (_set_invalid_parameter_handler_function != NULL) {
                _set_invalid_parameter_handler_function(myInvalidParameterHandler);
                printf("fixed dll %d\n", i);
            }
        }
    } else {
        printf("oops\n");
    }
    free(hModules);
}

For my real application, not this test, I get 1 dll fixed (msvcp90.dll). It still does not fix my problem.

I would appreciate any help in solving this.

4

3 回答 3

4

如果 dll 是使用静态链接的 CRT 构建的,则 CRT 的状态和功能将对 dll 的该实例是本地的。我假设 CRT 使用的无效参数处理程序正在UnhandledExceptionFilter从操作系统调用该函数,以显示“不错的”错误对话框。

您可以尝试挂钩类似UnhandledExceptionFilteror的函数TerminateProcess,使 dll 使用您自己的函数。你可以通过解析加载的dll的导入地址表,搜索你感兴趣的函数名,把地址改成指向你的函数。

于 2012-11-16T11:13:38.550 回答
1

您始终可以枚举进程中的模块,如果它是 C 运行时,则通过调用 GetProcAddress 来获取无效参数处理程序。

但是您最好尝试在根目录下修复错误。试图忽略这些问题大多只会导致进一步的问题,因为内存被破坏等等。

于 2011-06-21T20:51:33.627 回答
0

您可以创建另一个 DLL,它使用与导致调用无效参数处理程序的 DLL 使用的版本相同的 CRT 版本,并在该新 DLL 中注册无效参数处理程序。无效参数处理程序对进程/CRT 版本组合是全局的。

如果您不知道 DLL 使用的是什么版本并且无法弄清楚,最坏的情况是您创建了多个 DLL,每个 CRT 版本一个:

  • VS 6 静态/动态/多线程/单线程
  • VS.NET 静态/动态/多线程/单线程
  • VS 2003 静态/动态/多线程/单线程
  • VS 2005 静态/动态
  • VS 2008 静态/动态
  • VS 2010 静态/动态

您可以将它们创建为静态 .lib 文件并将它们全部链接到一个(非常混乱的)DLL 中。

于 2011-06-21T20:41:49.747 回答