2

私のプログラムはいくつかの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をロードします(それは私によって開発されていないので、そこでバグを修正するように指示する解決策を受け入れません)。そのファイル拡張子を呼び出しましょう。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で送信/送信しないダイアログが表示されないか、アプリケーションが7でダイアログの動作を停止します

David Gladfelterによると、私はやるべきです

void fixMyProblem() {
    _set_invalid_parameter_handler(myInvalidParameterHandler);
}

また、利用可能なバージョンCRTごとにこれを実行します。1つのバージョンの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)。それでも私の問題は解決しません。

これを解決するために助けていただければ幸いです。

4

3 に答える 3

4

dllが静的にリンクされたCRTで構築されている場合、CRTの状態と機能はdllのそのインスタンスに対してローカルになります。CRTで使用されている無効なパラメーターハンドラーがUnhandledExceptionFilter、OSから関数を呼び出して、「適切な」エラーダイアログを表示していると想定しています。

UnhandledExceptionFilterまたはのような関数をフックTerminateProcessして、代わりにdllに独自の関数を使用させることができます。これを行うには、ロードされたdllのインポートアドレステーブルを解析し、目的の関数名を検索して、関数を指すようにアドレスを変更します。

于 2012-11-16T11:13:38.550 に答える
1

プロセス内のモジュールをいつでも列挙できます。Cランタイムの場合は、GetProcAddressを呼び出して無効なパラメーターハンドラーを取得します。

ただし、ルートでバグを修正することをお勧めします。このような問題を無視しようとすると、メモリが破損するなどの理由で、さらに問題が発生することがほとんどです。

于 2011-06-21T20:51:33.627 に答える
0

DLLが使用するバージョンと同じバージョンのCRTを使用する別のDLLを作成して、無効なパラメーターハンドラーを呼び出し、無効なパラメーターハンドラーをその新しいDLLに登録することができます。無効なパラメータハンドラは、プロセス/CRTバージョンの組み合わせに対してグローバルです。

DLLが使用しているバージョンがわからず、理解できない場合、最悪の場合、CRTバージョンごとに1つずつ、複数のDLLを作成します。

  • VS6静的/動的/マルチスレッド/シングルスレッド
  • VS.NET静的/動的/マルチスレッド/シングルスレッド
  • VS2003静的/動的/マルチスレッド/シングルスレッド
  • VS2005静的/動的
  • VS2008静的/動的
  • VS2010静的/動的

おそらく、それらを静的な.libファイルとして作成し、それらすべてを1つの(非常に混乱した)DLLにリンクすることができます。

于 2011-06-21T20:41:49.747 に答える