<< Back


Because many of the FTP Voyager SDK functions can be asynchronous (non-blocking), the use of callback functions for certain events makes error handling and status updates easier. Callback functions are set in the FVSDK_Session structure. After initializing the FVSDK_Session structure, set the appropriate function pointers to the pointer of your callback functions. Be sure your function is declared the same way as the function pointer in order to ensure the correct stack popping. The following examples illustrate how to use some of these callback functions.

Transfer Status - pfnNotifyTransferStatus

The following C sample program, SampleC-Callback.c, sets the pfnNotifyTransferStatus and pfnDownloadError elements, downloads a file, and displays the transfer status as the file is being downloaded via the pfnNotifyTransferStatus callback function. If an error occurs during the transfer, a message is displayed via the pfnDownloadError callback function.

SampleC-Callback.c:

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include "FVSDK_Funcs.h"

void CALLBACK OnDownloadError(FVSDK_CALLBACK_DATA pvData, long nErr, long nCause, LPCTSTR pszError,
        LPCTSTR pszRemotePath, LPCTSTR pszDestFileName, LPCTSTR pszExtraInfo)
{
    // display a message
    // for definitions of possible nErr values, refer to FtpTreeErrors.h
    printf("A download error has occurred.\r\n\r\nnErr:\t\t\t%d\r\nlCause:\t\t\t%d\r\npszError:\t\t%s\r\nlpszFilePath:\t\t%s\r\nlpszDestFileName:\t%s\r\nlpszExtraInfo:\t%s\r\n",
                nErr, nCause, pszError, pszRemotePath, pszDestFileName, pszExtraInfo);
} // OnDownloadError


char* FormatDoubleStr(char* szBuf, int nBufSize, double dVal, int nPrec)
{
    char        szStr[256];
    NUMBERFMT   Num;

    // convert to text
    sprintf(szStr, "%.*lf", nPrec, dVal);

    // get locale information
    GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szBuf, 10);
    GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, &szBuf[10], 10);

    // the number of digits
    Num.NumDigits       = nPrec;
    Num.LeadingZero     = TRUE;
    Num.Grouping        = 3;
    Num.lpDecimalSep    = &szBuf[10];
    Num.lpThousandSep   = szBuf;
    Num.NegativeOrder   = 0;

    // convert the string to a readable form
    GetNumberFormat(LOCALE_USER_DEFAULT, 0, szStr, &Num, szBuf, nBufSize);

    // return the pointer to the output buffer
    return (szBuf);
} // FormatDoubleStr


void CALLBACK OnNotifyTransferStatus(FVSDK_CALLBACK_DATA pvData, UINT nStatus,
        FVSDK_TransferStatus* pTransferStatus)
{
    char    szBuf[256], szStatus[256];

    // the old status text is found in the callback data
    char* szOldStatus = (char *) pvData;

    // check if the transfer is complete
    if (nStatus == FVSDK_TRANSFER_END) {

        // the transfer is done
        strcpy(szStatus, "The transfer is complete.");
    } // if
    else {
        char    szStr[40];
        double  dBytesPerSec = pTransferStatus->dBytesPerSecond;

        // make it a bit easier to read
        if (dBytesPerSec <= 1024.00)
            strcpy(szStr, "Bytes");
        else if ((dBytesPerSec /= (double) 1024.00) < 1024.00)
            strcpy(szStr, "KB");
        else {
            strcpy(szStr, "MB");
            dBytesPerSec /= 1024.00;
        } // else 

        // build a string with the transfer rate and time remaining
        sprintf(szStatus, "Transfer: %02d:%02d:%02d (%s %s/sec)",
            pTransferStatus->dwRemainingHours,
            pTransferStatus->dwRemainingMinutes,
            pTransferStatus->dwRemainingSeconds,
            FormatDoubleStr(szBuf, sizeof(szBuf), dBytesPerSec, 2), szStr);
    } // else

    // update the display only if it's changed
    if (strcmp(szStatus, szOldStatus) != 0) {
        printf("%-70s\r", szStatus);
        strcpy(szOldStatus, szStatus);
    } // if
} // OnNotifyTransferStatus


int main(int argc, char* argv[])
{
    int             nRet = 0;
    char            szOldStatus[256];
    FVSDK_Session*  pSession;

    // clear the old status string
    memset(szOldStatus, '\0', sizeof(szOldStatus));

    // allocate and initialize the session in the SDK
    if (FVSDK_NewSession(&pSession) == FVSDK_OK) {

        // set the server name to connect to
        pSession->pszServer = "ftp.rhinosoft.com";

        // set the transfer status callback function
        pSession->pfnNotifyTransferStatus = OnNotifyTransferStatus;

        // set the "old status" string to be used as the data pointer to the transfer status callback
        pSession->pvNotifyTransferStatusData = szOldStatus;

        // set the download error callback
        pSession->pfnDownloadError = OnDownloadError;

        // no download overwrite confirmations
        pSession->bConfirmDownloadOverwrite = FALSE;

        // try to connect to the server
        if (FVSDK_Connect(pSession) == FVSDK_OK) {

            // download the file from the server
            if (FVSDK_Download(pSession, "/rhinosoft/serv-u/sugerman.exe", "C:\\Temp\\") != FVSDK_OK)
                nRet = 3;

            // disconnect from the server
            FVSDK_Disconnect(pSession);
        } // if
        else
            nRet = 2;

        // close and release the session
        FVSDK_FreeSession(pSession);
    } // if
    else
        nRet = 1;

    // display any error
    if (nRet)
        printf("\r\nerror: %d", nRet);

    // tell the user to press a key on the keyboard
    printf("\r\nPress any key --> ");

    // wait for the user to press a key on the keyboard
    getch();

    // exit from our application, 0 == success, otherwise an error
    return (nRet);
} // main

Click here for the complete list of callback functions found in the FVSDK_Session structure. Each of the functions is documented in detail with examples at the above link.