2015-07-21 56 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'。 –