Affected files: .obsidian/daily-notes.json .obsidian/plugins/periodic-notes/data.json .obsidian/templates.json .obsidian/workspace 01. 個人/02. 專注Study/Android/ADB 取得 APK 的 icon.md 01. 個人/02. 專注Study/Android/ADB.md 01. 個人/02. 專注Study/Android/AOSP.md 01. 個人/02. 專注Study/Android/Android programming.md 01. 個人/02. 專注Study/Android/Ktor.md 01. 個人/02. 專注Study/Android/Service.md 01. 個人/02. 專注Study/Android/Tools.md 01. 個人/02. 專注Study/Android/UI.md 01. 個人/02. 專注Study/C++/C++17.md 01. 個人/02. 專注Study/C++/Class template.md 01. 個人/02. 專注Study/C++/Structured binding declaration.md 01. 個人/02. 專注Study/C++/for_each.md 01. 個人/02. 專注Study/C++/lambda.md 01. 個人/02. 專注Study/C++/lvalue.md 01. 個人/02. 專注Study/C++/move operator.md 01. 個人/02. 專注Study/C++/rvalue.md 01. 個人/02. 專注Study/C++/智慧指標.md 01. 個人/02. 專注Study/RxKotlin/20200207 - Study RxKotlin.md 03. 資料收集/01. Programming/COM/20210726 - COM Interface.md 03. 資料收集/01. Programming/DB/MySQL.md 03. 資料收集/01. Programming/DB/sqlite.md 03. 資料收集/01. Programming/Design Pattern.md 03. 資料收集/01. Programming/FFMPEG/00. Introduction.md 03. 資料收集/01. Programming/FFMPEG/01. Setup.md 03. 資料收集/01. Programming/FFMPEG/FFMpeg.md 03. 資料收集/01. Programming/Flask.md 03. 資料收集/01. Programming/Media Foundation/20210604 - Windows media foundation.md 03. 資料收集/01. Programming/OpenCV.md 03. 資料收集/01. Programming/OpenGL.md 03. 資料收集/01. Programming/Python/argparse.ArgumentParser.md 03. 資料收集/01. Programming/Python/decorator.md 03. 資料收集/01. Programming/Python/logging.md 03. 資料收集/01. Programming/Python/opencv.md 03. 資料收集/01. Programming/Python/subprocess.md 03. 資料收集/01. Programming/Python/threading.md 03. 資料收集/01. Programming/Python/tkinter.md 03. 資料收集/01. Programming/Python/檢測工具.md 03. 資料收集/01. Programming/QT/Dropdown button.md 03. 資料收集/01. Programming/QT/QVariant.md 03. 資料收集/01. Programming/QT/Qt.md 03. 資料收集/01. Programming/UML.md 03. 資料收集/01. Programming/演算法.md 03. 資料收集/99. templates/blogHeader.md 03. 資料收集/99. templates/date.md 03. 資料收集/99. templates/front matter.md 03. 資料收集/99. templates/note.md 03. 資料收集/99. templates/table.md 03. 資料收集/99. templates/thisWeek.md 03. 資料收集/99. templates/日記.md 03. 資料收集/99. templates/讀書筆記.md 03. 資料收集/Hobby/RC.md 03. 資料收集/Hobby/RC/Traxxas Sledge.md 03. 資料收集/Hobby/RC/好盈電變調整中立點.md 03. 資料收集/Hobby/RC/差速器調教教學.md 03. 資料收集/Linux/CLI/cut.md 03. 資料收集/Linux/CLI/scp.md 03. 資料收集/Linux/CLI/timedatectl.md 03. 資料收集/Programming/Qt.md 03. 資料收集/Tool Setup/Hardware/RaspberryPi.md 03. 資料收集/Tool Setup/Software/Chrome.md 03. 資料收集/Tool Setup/Software/Obisidian.md 03. 資料收集/Tool Setup/Software/SublimeText.md 03. 資料收集/Tool Setup/Software/VirtualBox.md 03. 資料收集/Tool Setup/Software/Visual Studio Code.md 03. 資料收集/Tool Setup/Software/Windows Setup.md 03. 資料收集/Tool Setup/Software/Windows Terminal.md 03. 資料收集/Tool Setup/Software/freefilesync.md 03. 資料收集/Tool Setup/Software/vim.md 03. 資料收集/翻牆/V2Ray.md 03. 資料收集/翻牆/Wireguard.md 03. 資料收集/軟體工具/youtube-dl.md
2.0 KiB
2.0 KiB
IID_PPV_ARGS Marco
我们已经知道 CoCreateInstance 和 QueryInterface 函数的最后一个参数都是 void** 类型,这就会带来潜在的类型不匹配的安全问题,考虑下面的代码段:
// Wrong!
IFileOpenDialog *pFileOpen;
hr = CoCreateInstance(
__uuidof(FileOpenDialog),
NULL,
CLSCTX_ALL,
__uuidof(IFileDialogCustomize), // The IID does not match the pointer type!
reinterpret_cast<void**>(&pFileOpen) // Coerce to void**.
);
在这段代码中,想要获取的接口类型是 IFileDialogCustomize,但是传入的却是一个 IFileOpenDialog 类型的指针变量。reinterpret_cast 表达式会绕过 C++ 类型系统的检测,所以编译器并不会主动抛出错误。
如果这段代码被运行,好的结果是函数返回失败,无法找到该接口;而坏的结果是,函数会返回成功,而你将获得一个类型结果不匹配的指针。换句话说,这个指针类型没有匹配到内存中真实的虚函数表,如果你所想不会有啥好事发生。
一个虚函数表(virtual method table)是一个函数指针表,它被用来实现 COM 组件运行期间的动态绑定。这种方式也是大多数 C++ 编译器用来实现动态绑定(多态)的方法。
IID_PPV_ARGS 宏是一个帮助你避免类型错误的方法,使用方法如下:
__uuidof(IFileDialogCustomize), reinterpret_cast<void**>(&pFileOpen)
替换为
IID_PPV_ARGS(&pFileOpen)
这个宏会自动将 __uuidof(IFileOpenDialog) 参数插入。它可以保证你返回的接口指针类型的正确性。这是修改后的代码:
// Right.
IFileOpenDialog *pFileOpen;
hr = CoCreateInstance(__uuidof(FileOpenDialog), NULL, CLSCTX_ALL,
IID_PPV_ARGS(&pFileOpen));
你可以在 QueryInterface 函数中使用一样的宏:
IFileDialogCustomize *pCustom;
hr = pFileOpen->QueryInterface(IID_PPV_ARGS(&pCustom));