2015-07-21 58 views
0

我想讓我們知道我對C++比較陌生(因爲在同一天項目中提出兩個問題而感到內疚)。執行函數在調用函數三次之後崩潰


運行下面的環(或在取消對五個連續線主叫MyDownloadFunction然後運行)時,將導致應用程序崩潰。

錯誤消息:
terminate called after throwing an instance of 'std::ios_base::failure' what(): basic_ios::clear This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.

我想知道究竟是爲什麼,如果被調用的函數只有一次或兩次不會崩潰,但崩潰,如果它運行3次以上(和在第三次,該文件被正確保存),當然,如何解決它。

請假定https://MyWebsite.com存在這個問題。

#include <iostream> 
#include <sstream> 
// #include <stdio.h> 
// #include <string> 
#include <windows.h> 

using namespace std; 

int main() { 
    typedef int * (*MyDownloadToUrl)(void*, const char*, const char*, DWORD, void*); 
    HINSTANCE LibHnd = LoadLibrary("Urlmon.dll"); 
    MyDownloadToUrl MyDownloadFunction = (MyDownloadToUrl)GetProcAddress(LibHnd,"URLDownloadToFileA"); 

    stringstream URL; 
    stringstream Iteration; 

    // MyDownloadFunction(NULL, "https://google.ca", "Google 1.htm", 0, NULL); 
    // MyDownloadFunction(NULL, "https://google.ca", "Google 2.htm", 0, NULL); 
    // MyDownloadFunction(NULL, "https://google.ca", "Google 3.htm", 0, NULL); 
    // MyDownloadFunction(NULL, "https://google.ca", "Google 4.htm", 0, NULL); 
    // MyDownloadFunction(NULL, "https://google.ca", "Google 5.htm", 0, NULL); 

    for (int i = 1; i <= 5; i++) { 
     URL << "https://MyWebsite.com/" << i << "/"; 
     cout << URL.str() << "\r\n"; 

     Iteration << i << ".htm"; 
     cout << Iteration.str() << "\r\n\r\n"; 

     MyDownloadFunction(NULL, URL.str().c_str(), Iteration.str().c_str(), 0, NULL); 

     URL.str(""); 
     Iteration.str(""); 
    } 
} 

回答

1

URLDownloadToFile(和大多數,如果不是所有其他Windows API函數)使用stdcall調用約定而不是ccall約定。第一個也是最後一個參數不是void* s,它們是LPUNKNOWNLPBINDSTATUSCALLBACK,它返回HRESULT,而不是int*。通過指向不同類型的指針調用一種類型的函數是未定義的行爲。因此,您需要將您的typedef更改爲:

typedef HRESULT (__stdcall *MyDownloadToUrl)(LPUNKNOWN, const char*, const char*, DWORD, LPBINDSTATUSCALLBACK); 
+0

將'typedef'更改爲您提供的行會導致許多編譯器問題。另外,據我所知,'NULL'可以毫無問題地傳遞給'void *'(在文檔中,它告訴我們在不需要下載狀態時使用'NULL')。 –

+0

確實使用'void *'可能可以,但它是未定義的行爲。它可以完美工作,也可以重新格式化硬盤。該語言不能保證您在調用UB時會發生什麼。該typedef適用於我使用Visual Studio 2010.我沒有使用過mingw,但看起來你可能需要使用'__stdcall'而不是'_stdcall'。 –