簡單的說,我們調(diào)用別人的API叫call,調(diào)用的第三方api調(diào)用我們的函數(shù)叫回調(diào)(callback)
回調(diào)機制
比如,要拷貝一個文件,將1.pdf拷貝成1_copy.pdf。。。
方法:調(diào)用Windows API(系統(tǒng)函數(shù)庫)
里面有一個CopyFile函數(shù)
CopyFile("1.pdf", "2.pdf" ... );
這種調(diào)用就叫Call,即,調(diào)用別人的函數(shù)
何時需要 Callback ?
考慮:拷貝一個很大的文件(比如,1G的視頻文件)。。。。
這個拷貝過程需要一段時間。。。
如果用CopyFile(…),則需要默默等待、直到它完成。。。
缺點:用戶體驗差,缺少交互性
這時候,我們希望增加交互性:顯示拷貝的進度這意味著,我們希望系統(tǒng)在拷貝文件的時候,能夠通知我們的應用程序。。。
比如,我們提供一個函數(shù)
void CopyProgress(int total, int copied)
{
}
我們希望: 系統(tǒng)能夠時不時的調(diào)用我們的這個函數(shù),將total/copied數(shù)據(jù)通知給我們。。。
這時,我們將這個函數(shù)的地址作為參數(shù)傳給API即可
CopyFileEx(source, dst, &CopyProgress, NULL, NULL, 0);
示例代碼:
#include<windows.h>
#include<stdio.h>
// 將LARGE_INTTEGER類型轉(zhuǎn)成unsigned long long
unsigned long long translate(LARGE_INTEGER num)
{
unsigned long long result = num.HighPart;
result <<= 32;
result += num.LowPart;
return result;
}
// 回調(diào)函數(shù)
// 注:要求將此函數(shù)用關(guān)鍵字CALLBACK修飾(這是Windows API的要求)
DWORD CALLBACK CopyProgress(
LARGE_INTEGER TotalFileSize,
LARGE_INTEGER TotalBytesTransferred,
LARGE_INTEGER StreamSize,
LARGE_INTEGER StreamBytesTransferred,
DWORD dwStreamNumber,
DWORD dwCallbackReason,
HANDLE hSourceFile,
HANDLE hDestinationFile,
LPVOID lpData)
{
//文件的總字節(jié)數(shù) TotalFileSize
unsigned long long total = translate(TotalFileSize);
//已完成的字節(jié)數(shù) TotalBytesTransferred
unsigned long long copied = translate(TotalBytesTransferred);
//打印進度
//printf("進度:%I64d / %I64d \n", copied, total);// 64位整數(shù)用 %I64d
//printf("進度: %d / %d \n", (int)copied, (int)total); // 文件大小于2G時,可以轉(zhuǎn)成int
printf("%d%% \n", 100*copied / total);//按百分比顯示拷貝進度
return PROGRESS_CONTINUE;
}
int main()
{
const char* source = "c:\\test\\2.rmvb";
const char* dst = "c:\\test\\2_copy.rmvb";
printf("start copy ...\n");
// 將函數(shù)指針傳給CopyFileEx
BOOL result = CopyFileEx(source, dst, &CopyProgress, NULL, NULL, 0);
printf("operation done : %s \n", result ? "success" : "failed");
return 0;
}
2.回調(diào)函數(shù)中的上下文
使用回調(diào)函數(shù)時,總是會透傳一個void參數(shù),指向一個上下文對象。
"透傳":透明的,不關(guān)心其類型與內(nèi)容,什么樣的進來、什么樣的出去。。。void
注意:上下文對象的生命期在回調(diào)函數(shù)被觸發(fā)時,該上下文對象必須是有效的。。
我們希望在函數(shù)回調(diào)時顯示其他信息,文件名......
然而,在回調(diào)函數(shù)的參數(shù)里,并沒有源文件名和目標文件名。。。也就是說,無法得知當前正在拷貝的哪個文件。。。
在回調(diào)函數(shù)中參數(shù) “ lpData”即上下文,類型為“ LPVOID”也就是void*類型,
上下文對象:該對象攜帶了所有必要的上下文信息。。。
可以為任意類型的數(shù)據(jù),完全有用戶自己決定。。。
比如:
struct Context
{
char username[32];
char source[128];
char dst[128];
};
示例代碼:
#include<windows.h>
#include<stdio.h>
#include<string.h>
struct Context {
char username[32];
char source[128];
char dst[128];
};
// 將LARGE_INTTEGER類型轉(zhuǎn)成unsigned long long
unsigned long long translate(LARGE_INTEGER num)
{
unsigned long long result = num.HighPart;
result <<= 32;
result += num.LowPart;
return result;
}
// 回調(diào)函數(shù)
// 注:要求將此函數(shù)用關(guān)鍵字CALLBACK修飾(這是Windows API的要求)
DWORD CALLBACK CopyProgress(
LARGE_INTEGER TotalFileSize,
LARGE_INTEGER TotalBytesTransferred,
LARGE_INTEGER StreamSize,
LARGE_INTEGER StreamBytesTransferred,
DWORD dwStreamNumber,
DWORD dwCallbackReason,
HANDLE hSourceFile,
HANDLE hDestinationFile,
LPVOID lpData)
{
//文件的總字節(jié)數(shù) TotalFileSize
unsigned long long total = translate(TotalFileSize);
//已完成的字節(jié)數(shù) TotalBytesTransferred
unsigned long long copied = translate(TotalBytesTransferred);
//轉(zhuǎn)換上下文對象
Context* ctx = (Context*)lpData;
//打印進度
//printf("進度:%I64d / %I64d \n", copied, total);// 64位整數(shù)用 %I64d
//printf("進度: %d / %d \n", (int)copied, (int)total); // 文件大小于2G時,可以轉(zhuǎn)成int
printf("[%s]\t%s\t->\t%s\t%d%% \n",ctx->username,ctx->source,ctx->dst,(int)100*copied / total);//按百分比顯示拷貝進度
return PROGRESS_CONTINUE;
}
int main() {
//定義上下文對象
Context con;
strcpy_s(con.username, "NiceBlueChai");
strcpy_s(con.source, "E:\\與孩子一起學編程(中文完整版).pdf");
strcpy_s(con.dst, "e:\\1234.pdf");
const char* source = "E:/與孩子一起學編程(中文完整版).pdf";
const char* dst = "e:/1234.pdf";
//const char* source = "F:\\迅雷下載\\taxt/123.mkv";
//const char* dst = "F:\\迅雷下載\\taxt/出租車司機.mkv";
printf("start copy...\n");
system("color 70");
BOOL result = CopyFileEx(source, dst, &CopyProgress,&con,NULL,0);
printf("operation done:%s\n", result ? "success" : "filed");
getchar();
return 0;
}
??我的目標是:someday,即便你花錢看我的文章,也會覺得心滿意足