我的程序加载了几个dll并调用它们的函数。 dll可以使用不同版本的CRT。
当C运行时检查参数的有效性并发现问题时,它会调用无效参数句柄,无论是否有“发送 - 不发送”对话框,它都会关闭应用程序。
我尝试调用* _set_invalid_parameter_handler *,但只有从坏dll中调用它才有效。我尝试了 SetErrorMode ,但我设法做的就是在没有对话框的情况下杀死进程。
有没有办法处理这些异常?我不在乎某些资源是否受到损害。我想要的只是允许用户保存配置。如果出现对话框,则会单击该对话框并终止该过程。
修改 事实证明,加载所有版本的CRT或枚举所有DLL失败的解决方案。为了清楚起见,这里有一个小例子:
这将是我的主要应用程序(让我们调用文件 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();
}
这个应用程序加载一个做坏事的dll(它不是由我开发的,所以我不会接受任何解决方法告诉我修复那里的bug)。让我们称之为文件 extension.c 。
#include <stdio.h>
__declspec(dllexport) void function() {
printf("do bad stuff");
fopen(NULL, "r");
}
要编译,请执行:
cl extension.c /link /OUT:extension.dll /DLL
cl application.c
问题是我在函数 fixMyProblem()中该怎么办,所以我没有在XP或<上发送发送/不发送对话框em>应用程序已停止工作对话框7。
David Gladfelter认为我应该这样做
void fixMyProblem() {
_set_invalid_parameter_handler(myInvalidParameterHandler);
}
并为每个版本 CRT提供此功能。事实证明,即使使用单个版本的CRT(我对exe和dll使用相同的版本),它仍然无效。他们都使用CRT的相同版本,但似乎他们没有使用相同的 CRT。
如果是这种情况,我认为我必须更改的内容是在DLL内部。当然,它不会导出* _set_invalid_parameter_handler *。
但为了公平对待David Heffernan,这是他的解决方案的实施:
#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);
}
对于我的真实应用程序,不是这个测试,我得到1 dll修复(msvcp90.dll)。它仍然无法解决我的问题。
我很感激你解决这个问题的任何帮助。
答案 0 :(得分:4)
如果使用静态链接的CRT构建dll,则CRT的状态和功能将是该dll实例的本地和函数。
我假设CRT使用的无效参数处理程序正在从OS调用UnhandledExceptionFilter
函数,以显示“nice”错误对话框。
您可以尝试挂钩UnhandledExceptionFilter
或TerminateProcess
等函数,使dll使用您自己的函数。您可以通过解析加载的dll的导入地址表,搜索您感兴趣的函数名称,并将地址更改为指向您的函数来完成此操作。
答案 1 :(得分:1)
您始终可以枚举进程中的模块,如果它是C运行时,则通过调用GetProcAddress来获取无效参数处理程序。
但是你最好尝试修复根目录下的错误。试图忽略这些问题大多只会导致进一步的问题,因为内存会被破坏等等。
答案 2 :(得分:0)
您可以创建另一个DLL,它使用与DLL使用相同版本的CRT导致无效参数处理程序被调用,并在该新DLL中注册无效参数处理程序。无效参数处理程序对进程/ CRT版本组合是全局的。
如果你不知道DLL正在使用什么版本并且你无法弄清楚,最糟糕的情况是你创建几个DLL,每个CRT版本一个:
您可以将它们创建为静态.lib文件,并将它们全部链接到一个(非常混乱的)DLL中。