Click here to Skip to main content
15,902,299 members
Home / Discussions / C / C++ / MFC
   

C / C++ / MFC

 
AnswerRe: simple static library linking to dll issue. Pin
jschell16-Nov-11 10:00
jschell16-Nov-11 10:00 
QuestionURLDownloadToFile, Cancel Button Pin
jkirkerx15-Nov-11 15:09
professionaljkirkerx15-Nov-11 15:09 
AnswerRe: URLDownloadToFile, Cancel Button Pin
Chuck O'Toole15-Nov-11 16:19
Chuck O'Toole15-Nov-11 16:19 
GeneralRe: URLDownloadToFile, Cancel Button Pin
jkirkerx15-Nov-11 16:32
professionaljkirkerx15-Nov-11 16:32 
AnswerRe: URLDownloadToFile, Cancel Button Pin
Chuck O'Toole15-Nov-11 17:01
Chuck O'Toole15-Nov-11 17:01 
GeneralRe: URLDownloadToFile, Cancel Button Pin
jkirkerx15-Nov-11 17:19
professionaljkirkerx15-Nov-11 17:19 
GeneralRe: URLDownloadToFile, Cancel Button Pin
jkirkerx16-Nov-11 11:01
professionaljkirkerx16-Nov-11 11:01 
GeneralRe: URLDownloadToFile, Cancel Button Pin
enhzflep16-Nov-11 13:40
enhzflep16-Nov-11 13:40 
They're both a lot easier having done them than before. I had no idea about threads or sockets 2 1/2 weeks ago, but have now learnt enough to get by and have cobbled together a rss reader - one which can pre-load all subscribed feeds in parallel, each in it's own thread.

Notifying the main window of a thread's completion is the easier of the two. Without MFC, it's as (1) defining a user message, and deciding on the format (if any) of the passed information (2) sending that message to the main window upon completion (3) handling that message in the main window.

E.g
Part 1 - Main window completion notification mechanism
C++
#define WM_GALLERY_HTML_AVAILABLE WM_USER+1
#define WM_FILE_DOWNLOAD_COMPLETE WM_USER+2
...
...
...
__stdcall void galleryHtmlDownloadedCallbackFunc(PVOID data)
{
    downloadHeader_t *hdr;
    hdr = (downloadHeader_t*)data;

    galHtmlStr = hdr->result;
    galUrlStr = hdr->szUrl;

    free(hdr->result);
    hdr->result = NULL;
    hdr->contentLen = 0;

    PostMessage(mainDlgWnd, WM_GALLERY_HTML_AVAILABLE, 0, 0);
}

...
...
...
...

    case WM_INITDIALOG:
        mainDlgWnd = hwndDlg;
        editWnd = GetDlgItem(hwndDlg, IDC_RICHEDIT1);
        SetFocus(GetDlgItem(hwndDlg, IDC_RICHEDIT1));
        return FALSE;

    case WM_FILE_DOWNLOAD_COMPLETE:
        return true;

    case WM_GALLERY_HTML_AVAILABLE:
        findLinks((char*)galHtmlStr.c_str(), links, validExts);
        strLinks.clear();
        printf("Number of links: %d\n", links.size());
        for (i=0; i<links.size(); i++)
            strLinks += links[i] + "\n";
        SetDlgItemText(mainDlgWnd, IDC_RICHEDIT1, strLinks.c_str());
        return true;

    case WM_CLOSE:
        EndDialog(hwndDlg, 0);
        return TRUE;


Part 2 - Threading mechanism


C++
///////// usage example single (extra) thread //////////

    static downloadHeader_t curDownload;
    GetWindowText(urlHwnd, szUrl, urlLen+1);
    savePath = getFolderName(mainDlgWnd, "C:\\001");

    if (strlen(szUrl) && strlen(savePath))
    {
        curDownload.szUrl = szUrl;
        curDownload.callback = (voidFuncPtr)galleryHtmlDownloadedCallbackFunc;
        curDownload.saveFilePath = savePath;
        _beginthread(DownloadThread, NULL, (void*)&(curDownload));
    }

    delete savePath;
    delete szUrl;

////////////////////////////////////////////////////////////////////////


typedef void (*voidFuncPtr)(void*);
struct downloadHeader_t
{
    string szUrl;             // in
    voidFuncPtr callback;     // in
    string saveFilePath;     // in
    PVOID lParam;             // in

    SOCKET conn;
    char *readBuffer, *sendBuffer, *tmpBuffer, *result;
    string server, filepath, filename;
    long thisReadSize, headerLen, contentLen;
};


// seperate a url into it's components
void mParseUrl(char *mUrl, string &serverName, string &filepath, string &filename)
{
    string::size_type n;
    string url = mUrl;

    if (url.substr(0,7) == "http://")
        url.erase(0,7);

    n = url.find('/');
    if (n != string::npos)
    {
        serverName = url.substr(0,n);
        filepath = url.substr(n);
        n = filepath.rfind('/');
        filename = filepath.substr(n+1);
    }

    else
    {
        serverName = url;
        filepath = "/";
        filename = "";
    }
}


// return the socket number for a TCP connection
SOCKET connectToServer(char *szServerName, WORD portNum)
{
    struct hostent *hp;
    unsigned int addr;
    struct sockaddr_in server;
    SOCKET conn;
//SOCKHANDLE_USE_OVERLAPPED
    conn = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (conn == INVALID_SOCKET)
        return NULL;

    if(inet_addr(szServerName)==INADDR_NONE)
    {
        hp=gethostbyname(szServerName);
    }
    else
    {
        addr=inet_addr(szServerName);
        hp=gethostbyaddr((char*)&addr,sizeof(addr),AF_INET);
    }

    if(hp==NULL)
    {
        closesocket(conn);
        return NULL;
    }

    server.sin_addr.s_addr=*((unsigned long*)hp->h_addr);
    server.sin_family=AF_INET;
    server.sin_port=htons(portNum);
    if(connect(conn,(struct sockaddr*)&server,sizeof(server)))
    {
        closesocket(conn);
        return NULL;
    }
    return conn;
}

// searches the content returned from a server for 2 newlines in a row - this signifies the end of the header.
// the RFC (I forget the number) states that "\r\n\r\n" to be the valid terminator, however not all sites conform
// to the standard.
int getHeaderLength(char *content)
{
    const char *srchStr1 = "\r\n\r\n", *srchStr2 = "\n\r\n\r";
    char *findPos;
    int ofset = -1;

    findPos = strstr(content, srchStr1);
    if (findPos != NULL)
    {
        ofset = findPos - content;
        ofset += strlen(srchStr1);
    }

    else
    {
        findPos = strstr(content, srchStr2);
        if (findPos != NULL)
        {
            ofset = findPos - content;
            ofset += strlen(srchStr2);
        }
    }
    return ofset;
}






/*
struct downloadHeader_t
{
    string szUrl;            // in
    voidFuncPtr callback;     // in
    channelDef_t *channel;  // in

    SOCKET conn;
    char *readBuffer, *sendBuffer, *tmpBuffer, *result;
    string server, filepath, filename;
    long thisReadSize, headerLen, contentLen;
};
*/
void __stdcall DownloadThread(void *dat)
{
    downloadHeader_t *hdr;
    hdr = (downloadHeader_t *)dat;
    const int bufSize = 512;

    printf("download thread - \n");

    hdr->result = NULL;
    hdr->readBuffer = (char*)malloc(bufSize);
    hdr->sendBuffer = (char*)malloc(bufSize);
    hdr->tmpBuffer = (char*)malloc(bufSize);

    printf("download thread - \n");

    mParseUrl((char*)hdr->szUrl.c_str(), hdr->server, hdr->filepath, hdr->filename);

    printf("download thread - \n");
//http://forums.devshed.com/c-programming-42/any-ideas-863939.html
    ///////////// step 1, connect //////////////////////
//    printf("connecting to %s\n", hdr->server.c_str());
    hdr->conn = connectToServer((char*)hdr->server.c_str(), 80);
    if (hdr->conn)
        printf("download thread - connected?\n");

    ///////////// step 2, send GET request /////////////
    sprintf(hdr->tmpBuffer, "GET %s HTTP/1.0", hdr->filepath.c_str());
    strcpy(hdr->sendBuffer, hdr->tmpBuffer);
    strcat(hdr->sendBuffer, "\r\n");
    sprintf(hdr->tmpBuffer, "Host: %s", hdr->server.c_str());
    strcat(hdr->sendBuffer, hdr->tmpBuffer);
    strcat(hdr->sendBuffer, "\r\n");
    strcat(hdr->sendBuffer, "\r\n");
//    printf("sending:\n'%s'", hdr->sendBuffer);
    send(hdr->conn, hdr->sendBuffer, strlen(hdr->sendBuffer), 0);

    ///////////// step 3 - get received bytes ////////////////
    // Receive until the peer closes the connection
    hdr->contentLen = 0;
    while(1)
    {
        memset(hdr->readBuffer, 0, bufSize);
        hdr->thisReadSize = recv (hdr->conn, hdr->readBuffer, bufSize, 0);
        if ( hdr->thisReadSize <= 0 )
            break;

        // nasty - but seemingly necessary. Headers don't always include the content-length
        // without a known content length, we cannot accurately allocate the memory required to hold
        // the full (header+message) response. Therefore, we re-allocate our memory each time a successful read is performed.
        // the alternative would be to write directly to file, or allocate (hopefully) more memory than we
        // need (Too bad if we allocate 10 Mb & a resource is 10.1 Mb !)
        hdr->result = (char*)realloc(hdr->result, hdr->thisReadSize+hdr->contentLen);

        memcpy(hdr->result+hdr->contentLen, hdr->readBuffer, hdr->thisReadSize);
        hdr->contentLen += hdr->thisReadSize;
    }

    hdr->headerLen = getHeaderLength(hdr->result);
    hdr->contentLen -= hdr->headerLen;
    memmove(hdr->result, hdr->result+hdr->headerLen, hdr->contentLen);
    realloc(hdr->result, hdr->contentLen+1);
    hdr->result[hdr->contentLen] = 0x0;
    closesocket(hdr->conn);
    free(hdr->readBuffer);
    free(hdr->sendBuffer);
    free(hdr->tmpBuffer);

    if (hdr->callback)
        hdr->callback(hdr);
}

GeneralRe: URLDownloadToFile, Cancel Button Pin
jkirkerx17-Nov-11 6:15
professionaljkirkerx17-Nov-11 6:15 
GeneralRe: URLDownloadToFile, Cancel Button Pin
enhzflep17-Nov-11 19:45
enhzflep17-Nov-11 19:45 
GeneralRe: URLDownloadToFile, Cancel Button Pin
jkirkerx18-Nov-11 6:33
professionaljkirkerx18-Nov-11 6:33 
GeneralRe: URLDownloadToFile, Cancel Button Pin
enhzflep18-Nov-11 14:15
enhzflep18-Nov-11 14:15 
GeneralRe: URLDownloadToFile, Cancel Button Pin
jkirkerx18-Nov-11 17:05
professionaljkirkerx18-Nov-11 17:05 
AnswerRe: URLDownloadToFile, Cancel Button Pin
Chuck O'Toole18-Nov-11 17:25
Chuck O'Toole18-Nov-11 17:25 
GeneralRe: URLDownloadToFile, Cancel Button Pin
jkirkerx18-Nov-11 18:02
professionaljkirkerx18-Nov-11 18:02 
GeneralRe: URLDownloadToFile, Cancel Button Pin
enhzflep18-Nov-11 20:28
enhzflep18-Nov-11 20:28 
GeneralRe: URLDownloadToFile, Cancel Button Pin
jkirkerx19-Nov-11 7:15
professionaljkirkerx19-Nov-11 7:15 
GeneralRe: URLDownloadToFile, Cancel Button Pin
enhzflep19-Nov-11 15:00
enhzflep19-Nov-11 15:00 
GeneralRe: URLDownloadToFile, Cancel Button Pin
jkirkerx19-Nov-11 17:52
professionaljkirkerx19-Nov-11 17:52 
GeneralRe: URLDownloadToFile, Cancel Button Pin
enhzflep20-Nov-11 0:56
enhzflep20-Nov-11 0:56 
GeneralRe: URLDownloadToFile, Cancel Button Pin
jkirkerx20-Nov-11 18:06
professionaljkirkerx20-Nov-11 18:06 
QuestionProblem with MSDN Preview Handler Recipe Pin
AndrewG123115-Nov-11 13:26
AndrewG123115-Nov-11 13:26 
QuestionOT - question for real COM / RS232 guru Pin
Vaclav_15-Nov-11 10:33
Vaclav_15-Nov-11 10:33 
AnswerRe: OT - question for real COM / RS232 guru Pin
Richard MacCutchan15-Nov-11 22:00
mveRichard MacCutchan15-Nov-11 22:00 
GeneralRe: OT - question for real COM / RS232 guru Pin
Vaclav_16-Nov-11 2:50
Vaclav_16-Nov-11 2:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.