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.
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.
#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.