2011-05-24 31 views
2

我的程序加載了幾個dll並調用它們的函數。 dll可以使用不同版本的CRT。禁止或攔截來自其他dll的CRT實例的CRT檢查

當C運行時檢查參數的有效性並發現問題時,它會調用無效參數句柄,從而關閉應用程序,可以使用或不使用「發送 - 不發送」對話框。

我試着調用* _set_invalid_parameter_handler *,但它只適用於從壞dll內調用它。我試過SetErrorMode,但我所做的只是在沒有對話框的情況下終止進程。

有什麼辦法來處理這些異常?我不在乎一些資源是否受到損害。我只想讓用戶保存配置。如果對話框出現,他們點擊它並殺死進程。


EDIT 原來的溶液加載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,做不好的事情(它不是我開發的,所以我不會接受任何解決方案告訴我修復那裏的錯誤)。讓我們打電話給那個文件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或應用程序對話框已停止工作對話框7.

據大衛Gladfelter我應該做的

void fixMyProblem() { 
    _set_invalid_parameter_handler(myInvalidParameterHandler); 
} 

而且還爲每個版本 CRT可用。事實證明,即使使用單一版本的CRT(我對exe和dll都使用相同的版本),它仍然不起作用。他們都使用CRT的相同版本,但似乎他們不使用相同的 CRT。

如果是這樣的話,我認爲我必須改變的東西在DLL裏面。當然,它不會導出* _set_invalid_parameter_handler *。

但平心而論大衛赫弗南,這裏是他的解決方案的實施:

#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

如果dll是使用靜態鏈接的CRT構建的,那麼CRT的狀態和功能將在dll的該實例的本地。 我假設CRT使用的無效參數處理程序正在調用UnhandledExceptionFilter函數,從操作系統,以顯示「很好」的錯誤對話框。

你可以嘗試掛鉤像UnhandledExceptionFilterTerminateProcess這樣的函數,讓dll使用你自己的函數。您可以通過解析加載的dll的導入地址表,搜索您感興趣的函數名稱,並將地址更改爲指向您的函數來完成此操作。

+0

該操作必須在我加載的所有DLL上完成,但實際上它工作正常。 – andi 2012-11-16 16:24:03

0

您可以創建另一個DLL,它使用與DLL使用的版本相同的CRT版本,該版本會導致無效參數處理程序被調用並將無效參數處理程序註冊到該新DLL中。無效參數處理程序對進程/ CRT版本組合是全局的。

如果你不知道該DLL正在使用什麼版本的,你不能弄清楚,最壞的情況是你創建幾個DLL的,每個CRT版本:

  • VS 6靜態/動態/多線程/單線程
  • VS.NET靜態/動態/多線程/單線程
  • VS 2003的靜態/動態/多線程/單線程
  • VS 2005的靜態/動態
  • 2008年靜態VS /動態
  • VS 2010的靜態/動態

你也許可以創建爲靜態.lib文件,並將它們全部連接成一個(非常困惑)DLL。

+0

儘管我真的不喜歡這個想法,但我必須承認,到現在爲止,這是第一個能夠真正解決問題的人。當然,如果出現新的CRT運行時,我的應用程序會再次受到攻擊。我必須看看這種努力是否值得遇到麻煩。如果幾天內沒有其他解決方案出現,我會接受這個答案作爲正確答案。 – andi 2011-06-22 07:04:57

1

您可以始終枚舉進程中的模塊,並且如果它是C運行庫,那麼通過調用GetProcAddress來獲取無效參數處理程序。

但是你最好試着修復root下的錯誤。試圖忽略這些問題通常會導致進一步的問題,因爲內存被損壞等等。

+0

如果有任何使用Dependency Walker的導出函數,我已經在發佈問題之前進行了檢查。我在那裏看不到_set_invalid_parameter_handler符號。 – andi 2011-06-22 06:56:40

+0

請編輯問題以包含此信息。另外你爲什麼不修復錯誤?當然這是最好的解決方案。 – 2011-06-22 07:11:07

+0

我可以在我看到的C運行時中找到'_set_invalid_parameter_handler'符號。我認爲你看錯了地方。 – 2011-06-22 13:07:34