首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >禁止或拦截来自其他dll的CRT实例的CRT检查。

禁止或拦截来自其他dll的CRT实例的CRT检查。
EN

Stack Overflow用户
提问于 2011-05-24 16:45:50
回答 3查看 1.1K关注 0票数 2

我的程序加载了几个dll并调用它们的函数。dlls可以使用不同版本的CRT。

当C运行时检查参数的有效性并发现问题时,它会调用无效的参数句柄,这反过来会关闭应用程序,不管是否使用“发送-不发送”对话框。

我试着调用*_set_invalid_parameter_handler*,但是只有在从坏的dll中调用它时,它才能工作。我尝试了SetErrorMode,但是我所做的就是在没有对话框的情况下杀死进程。

有什么办法处理这些例外吗?我不在乎某些资源是否受到损害。我只想让用户保存配置。如果出现该对话框,则他们单击它并终止该进程。

编辑原来是加载所有版本的或枚举所有all失败的解决方案。为了说明这一点,下面是一个小例子:

这将是我的主要应用程序(让我们调用文件应用程序。c):

代码语言:javascript
复制
#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 (它不是由我开发的,所以我不会接受任何告诉我修复错误的解决方案)。让我们调用那个文件扩展名.c。

代码语言:javascript
复制
#include <stdio.h>

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

要编译,请做:

代码语言:javascript
复制
cl extension.c /link /OUT:extension.dll /DLL
cl application.c

问题是在函数fixMyProblem()中做什么,这样就不会在XP上得到发送/不发送对话框,或者应用程序在7上停止工作对话框。

根据大卫·格拉德费尔特的说法我应该这么做

代码语言:javascript
复制
void fixMyProblem() {
    _set_invalid_parameter_handler(myInvalidParameterHandler);
}

也可以为每个版本的 CRT执行此操作。事实证明,即使只有一个版本的CRT (我对exe和dll都使用相同的版本),它仍然不能工作。它们都使用相同版本的,但似乎它们不使用相同的 CRT。

如果是这样的话,我假设我必须更改的内容在DLL中。当然,它不导出*_set_invalid_parameter_handler*。

但公平地说,大卫·赫弗南的解决方案如下:

代码语言:javascript
复制
#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);
}

对于我的实际应用程序,而不是这个测试,我修复了一个dll (msvcp90.dll)。它仍然不能解决我的问题。

如果能帮忙解决这个问题,我将不胜感激。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-11-16 11:13:38

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

您可以尝试连接像UnhandledExceptionFilterTerminateProcess这样的函数,让dll使用您自己的函数。您可以通过解析加载dll的Import表,搜索您感兴趣的函数名,并将地址更改为指向您的函数来实现这一点。

票数 4
EN

Stack Overflow用户

发布于 2011-06-21 20:51:33

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

但你最好试着从根本上解决问题。试图忽略这些问题通常只会导致更多的问题,因为内存会被破坏等等。

票数 1
EN

Stack Overflow用户

发布于 2011-06-21 20:41:49

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

如果您不知道DLL使用的是哪个版本,并且无法确定它,最糟糕的情况是您创建了几个DLL,每个CRT版本一个:

static/dynamic/multithreaded/single-threaded

  • VS.NET static/dynamic/multithreaded/single-threaded

  • VS 2003 static/dynamic/multithreaded/single-threaded

  • VS 2005 static/dynamic

  • VS 2008 static/dynamic

  • VS 2010 static/dynamic

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6113898

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档