LNK2019 示例来自 MSDN
LNK2019 with a sample from MSDN
试图从 Common File Dialog Sample got some LNK2019 中的 .cpp 文件复制代码。链接 3 个函数似乎有问题。
以下是错误:
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol __imp_TaskDialog referenced in function "public: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl CDialogEventHandler::ChooseFromFolder(void)" (?ChooseFromFolder@CDialogEventHandler@@QEAA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) Build-A-Font C:\Users\nadav\Desktop\SFML\Build-A-Font\Build-A-Font\FileDialog.obj 1
Error LNK2019 unresolved external symbol __imp_PSGetPropertyDescriptionListFromString referenced in function "public: virtual long __cdecl CDialogEventHandler::OnTypeChange(struct IFileDialog *)" (?OnTypeChange@CDialogEventHandler@@UEAAJPEAUIFileDialog@@@Z) Build-A-Font C:\Users\nadav\Desktop\SFML\Build-A-Font\Build-A-Font\FileDialog.obj 1
Error LNK2019 unresolved external symbol QISearch referenced in function "public: virtual long __cdecl CDialogEventHandler::QueryInterface(struct _GUID const &,void * *)" (?QueryInterface@CDialogEventHandler@@UEAAJAEBU_GUID@@PEAPEAX@Z) Build-A-Font C:\Users\nadav\Desktop\SFML\Build-A-Font\Build-A-Font\FileDialog.obj 1
这是他们根据我的需要修改后的代码:
#pragma once
#define STRICT_TYPED_ITEMIDS
#include <shlobj.h>
#include <shlwapi.h>
#include <string>
#include <sstream>
#pragma comment(linker, "\"/manifestdependency:type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
// Added for changing the entry point
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
const COMDLG_FILTERSPEC c_rgSaveTypes[] =
{
{L"Word Document (*.doc; *.docx)", L"*.doc;*.docx"},
{L"Powerpoint Presentation (*.ppt; *.pptx)", L"*.ppt;*.pptx"},
{L"Web Page (*.htm; *.html)", L"*.htm;*.html"},
{L"Text Document (*.txt)", L"*.txt"},
{L"All Documents (*.*)", L"*.*"}
};
// Indices of file types
#define INDEX_WORDDOC 1
#define INDEX_PRPNTPR 2
#define INDEX_WEBPAGE 3
#define INDEX_TEXTDOC 4
// Controls
#define CONTROL_GROUP 2000
#define CONTROL_RADIOBUTTONLIST 2
#define CONTROL_RADIOBUTTON1 1
#define CONTROL_RADIOBUTTON2 2 // It is OK for this to have the same ID as CONTROL_RADIOBUTTONLIST,
// because it is a child control under CONTROL_RADIOBUTTONLIST
// IDs for the Task Dialog Buttons
#define IDC_BASICFILEOPEN 100
/* File Dialog Event Handler *****************************************************************************************************/
class CDialogEventHandler : public IFileDialogEvents,
public IFileDialogControlEvents
{
public:
// IUnknown methods
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv)
{
static const QITAB qit[] = {
QITABENT(CDialogEventHandler, IFileDialogEvents),
QITABENT(CDialogEventHandler, IFileDialogControlEvents),
{ 0 },
#pragma warning(suppress:4838)
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&_cRef);
}
IFACEMETHODIMP_(ULONG) Release()
{
long cRef = InterlockedDecrement(&_cRef);
if (!cRef)
delete this;
return cRef;
}
// IFileDialogEvents methods
IFACEMETHODIMP OnFileOk(IFileDialog*) { return S_OK; };
IFACEMETHODIMP OnFolderChange(IFileDialog*) { return S_OK; };
IFACEMETHODIMP OnFolderChanging(IFileDialog*, IShellItem*) { return S_OK; };
IFACEMETHODIMP OnHelp(IFileDialog*) { return S_OK; };
IFACEMETHODIMP OnSelectionChange(IFileDialog*) { return S_OK; };
IFACEMETHODIMP OnShareViolation(IFileDialog*, IShellItem*, FDE_SHAREVIOLATION_RESPONSE*) { return S_OK; };
IFACEMETHODIMP OnOverwrite(IFileDialog*, IShellItem*, FDE_OVERWRITE_RESPONSE*) { return S_OK; };
// This method gets called when the file-type is changed (combo-box selection changes).
// For sample sake, let's react to this event by changing the properties show.
IFACEMETHODIMP OnTypeChange(IFileDialog* pfd)
{
IFileSaveDialog* pfsd;
HRESULT hr = pfd->QueryInterface(&pfsd);
if (SUCCEEDED(hr))
{
UINT uIndex;
hr = pfsd->GetFileTypeIndex(&uIndex); // index of current file-type
if (SUCCEEDED(hr))
{
IPropertyDescriptionList* pdl = NULL;
switch (uIndex)
{
case INDEX_WORDDOC:
// When .doc is selected, let's ask for some arbitrary property, say Title.
hr = PSGetPropertyDescriptionListFromString(L"prop:System.Title", IID_PPV_ARGS(&pdl));
if (SUCCEEDED(hr))
{
// FALSE as second param == do not show default properties.
hr = pfsd->SetCollectedProperties(pdl, FALSE);
pdl->Release();
}
break;
case INDEX_WEBPAGE:
// When .html is selected, let's ask for some other arbitrary property, say Keywords.
hr = PSGetPropertyDescriptionListFromString(L"prop:System.Keywords", IID_PPV_ARGS(&pdl));
if (SUCCEEDED(hr))
{
// FALSE as second param == do not show default properties.
hr = pfsd->SetCollectedProperties(pdl, FALSE);
pdl->Release();
}
break;
case INDEX_TEXTDOC:
// When .txt is selected, let's ask for some other arbitrary property, say Author.
hr = PSGetPropertyDescriptionListFromString(L"prop:System.Author", IID_PPV_ARGS(&pdl));
if (SUCCEEDED(hr))
{
// TRUE as second param == show default properties as well, but show Author property first in list.
hr = pfsd->SetCollectedProperties(pdl, TRUE);
pdl->Release();
}
break;
}
}
pfsd->Release();
}
return hr;
};
// IFileDialogControlEvents methods
// This method gets called when an dialog control item selection happens (radio-button selection. etc).
// For sample sake, let's react to this event by changing the dialog title.
IFACEMETHODIMP OnItemSelected(IFileDialogCustomize* pfdc, DWORD dwIDCtl, DWORD dwIDItem)
{
IFileDialog* pfd = NULL;
HRESULT hr = pfdc->QueryInterface(&pfd);
if (SUCCEEDED(hr))
{
if (dwIDCtl == CONTROL_RADIOBUTTONLIST)
{
switch (dwIDItem)
{
case CONTROL_RADIOBUTTON1:
hr = pfd->SetTitle(L"Longhorn Dialog");
break;
case CONTROL_RADIOBUTTON2:
hr = pfd->SetTitle(L"Vista Dialog");
break;
}
}
pfd->Release();
}
return hr;
};
IFACEMETHODIMP OnButtonClicked(IFileDialogCustomize*, DWORD) { return S_OK; };
IFACEMETHODIMP OnCheckButtonToggled(IFileDialogCustomize*, DWORD, BOOL) { return S_OK; };
IFACEMETHODIMP OnControlActivating(IFileDialogCustomize*, DWORD) { return S_OK; };
CDialogEventHandler() : _cRef(1) { };
private:
~CDialogEventHandler() { };
long _cRef;
};
// Instance creation helper
HRESULT CDialogEventHandler_CreateInstance(REFIID riid, void** ppv)
{
*ppv = NULL;
CDialogEventHandler* pDialogEventHandler = new (std::nothrow) CDialogEventHandler();
HRESULT hr = pDialogEventHandler ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
hr = pDialogEventHandler->QueryInterface(riid, ppv);
pDialogEventHandler->Release();
}
return hr;
}
// This code snippet demonstrates how to work with the common file dialog interface
std::string BasicFileOpen()
{
// CoCreate the File Open Dialog object.
IFileDialog* pfd = NULL;
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr))
{
// Create an event handling object, and hook it up to the dialog.
IFileDialogEvents* pfde = NULL;
hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
if (SUCCEEDED(hr))
{
// Hook up the event handler.
DWORD dwCookie;
hr = pfd->Advise(pfde, &dwCookie);
if (SUCCEEDED(hr))
{
// Set the options on the dialog.
DWORD dwFlags;
// Before setting, always get the options first in order not to override existing options.
hr = pfd->GetOptions(&dwFlags);
if (SUCCEEDED(hr))
{
// In this case, get shell items only for file system items.
hr = pfd->SetOptions(dwFlags | FOS_FORCEFILESYSTEM);
if (SUCCEEDED(hr))
{
// Set the file types to display only. Notice that, this is a 1-based array.
hr = pfd->SetFileTypes(ARRAYSIZE(c_rgSaveTypes), c_rgSaveTypes);
if (SUCCEEDED(hr))
{
// Set the selected file type index to Word Docs for this example.
hr = pfd->SetFileTypeIndex(INDEX_WORDDOC);
if (SUCCEEDED(hr))
{
// Set the default extension to be ".doc" file.
hr = pfd->SetDefaultExtension(L"doc");
if (SUCCEEDED(hr))
{
// Show the dialog
hr = pfd->Show(NULL);
if (SUCCEEDED(hr))
{
// Obtain the result, once the user clicks the 'Open' button.
// The result is an IShellItem object.
IShellItem* psiResult;
hr = pfd->GetResult(&psiResult);
if (SUCCEEDED(hr))
{
// We are just going to print out the name of the file for sample sake.
PWSTR pszFilePath = NULL;
hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
if (SUCCEEDED(hr))
{
TaskDialog(NULL,
NULL,
L"CommonFileDialogApp",
pszFilePath,
NULL,
TDCBF_OK_BUTTON,
TD_INFORMATION_ICON,
NULL);
CoTaskMemFree(pszFilePath);
}
psiResult->Release();
}
}
}
}
}
}
}
// Unhook the event handler.
pfd->Unadvise(dwCookie);
}
pfde->Release();
}
pfd->Release();
}
TCHAR filepath[1024];
if (hr == S_OK)
{
std::stringstream pff;
pff << filepath;
return pff.str();
}
return "";
}
我在从 github 下载的原始文件中更改了他们的代码,它工作得很好。我试图将它复制到另一个项目,但它不起作用(LNK2019 错误)
我想我会为此提供一种 meta-answer:Jerry 怎么知道你需要 link 使用哪些库? 而且,一如既往,答案就在文档中。
首先,让我们看看那些 linker 错误(为了清楚起见,我将它们删减了一些,使用模板通常会导致冗长/难以阅读的错误消息):
Unresolved symbol __imp_TaskDialog referenced in function <irrelevant>
Unresolved symbol __imp_PSGetPropertyDescriptionListFromString referenced in function <irrelevant>
Unresolved symbol QISearch referenced in function <irrelevant>
首先,您可以忽略 __imp_
位。这只是告诉您该函数是从 DLL 导入的。所以这给我们留下了以下未解决的参考:
TaskDialog
PSGetPropertyDescriptionListFromString
QISearch
所以,是时候去谷歌搜索了。
TaskDialog
的文档是 here,如果您向下滚动到页面底部的 'requirements' 部分,您将看到:
Library Comctl32.lib
这就是那个(请注意,这里的大小写无关紧要,我不知道为什么 Microsoft 以如此奇怪的方式记录这些内容)。
同理,我们很容易发现PSGetPropertyDescriptionListFromString
is in Propsys.lib
, and QISearch
在Shlwapi.lib
中。故事结束。
我希望向您展示它是如何完成的。每个 Windows 开发人员都需要了解如何执行此操作以及如何查找和阅读 Microsoft 通常提供的(大量)文档。
试图从 Common File Dialog Sample got some LNK2019 中的 .cpp 文件复制代码。链接 3 个函数似乎有问题。 以下是错误:
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol __imp_TaskDialog referenced in function "public: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl CDialogEventHandler::ChooseFromFolder(void)" (?ChooseFromFolder@CDialogEventHandler@@QEAA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) Build-A-Font C:\Users\nadav\Desktop\SFML\Build-A-Font\Build-A-Font\FileDialog.obj 1
Error LNK2019 unresolved external symbol __imp_PSGetPropertyDescriptionListFromString referenced in function "public: virtual long __cdecl CDialogEventHandler::OnTypeChange(struct IFileDialog *)" (?OnTypeChange@CDialogEventHandler@@UEAAJPEAUIFileDialog@@@Z) Build-A-Font C:\Users\nadav\Desktop\SFML\Build-A-Font\Build-A-Font\FileDialog.obj 1
Error LNK2019 unresolved external symbol QISearch referenced in function "public: virtual long __cdecl CDialogEventHandler::QueryInterface(struct _GUID const &,void * *)" (?QueryInterface@CDialogEventHandler@@UEAAJAEBU_GUID@@PEAPEAX@Z) Build-A-Font C:\Users\nadav\Desktop\SFML\Build-A-Font\Build-A-Font\FileDialog.obj 1
这是他们根据我的需要修改后的代码:
#pragma once
#define STRICT_TYPED_ITEMIDS
#include <shlobj.h>
#include <shlwapi.h>
#include <string>
#include <sstream>
#pragma comment(linker, "\"/manifestdependency:type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
// Added for changing the entry point
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
const COMDLG_FILTERSPEC c_rgSaveTypes[] =
{
{L"Word Document (*.doc; *.docx)", L"*.doc;*.docx"},
{L"Powerpoint Presentation (*.ppt; *.pptx)", L"*.ppt;*.pptx"},
{L"Web Page (*.htm; *.html)", L"*.htm;*.html"},
{L"Text Document (*.txt)", L"*.txt"},
{L"All Documents (*.*)", L"*.*"}
};
// Indices of file types
#define INDEX_WORDDOC 1
#define INDEX_PRPNTPR 2
#define INDEX_WEBPAGE 3
#define INDEX_TEXTDOC 4
// Controls
#define CONTROL_GROUP 2000
#define CONTROL_RADIOBUTTONLIST 2
#define CONTROL_RADIOBUTTON1 1
#define CONTROL_RADIOBUTTON2 2 // It is OK for this to have the same ID as CONTROL_RADIOBUTTONLIST,
// because it is a child control under CONTROL_RADIOBUTTONLIST
// IDs for the Task Dialog Buttons
#define IDC_BASICFILEOPEN 100
/* File Dialog Event Handler *****************************************************************************************************/
class CDialogEventHandler : public IFileDialogEvents,
public IFileDialogControlEvents
{
public:
// IUnknown methods
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv)
{
static const QITAB qit[] = {
QITABENT(CDialogEventHandler, IFileDialogEvents),
QITABENT(CDialogEventHandler, IFileDialogControlEvents),
{ 0 },
#pragma warning(suppress:4838)
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&_cRef);
}
IFACEMETHODIMP_(ULONG) Release()
{
long cRef = InterlockedDecrement(&_cRef);
if (!cRef)
delete this;
return cRef;
}
// IFileDialogEvents methods
IFACEMETHODIMP OnFileOk(IFileDialog*) { return S_OK; };
IFACEMETHODIMP OnFolderChange(IFileDialog*) { return S_OK; };
IFACEMETHODIMP OnFolderChanging(IFileDialog*, IShellItem*) { return S_OK; };
IFACEMETHODIMP OnHelp(IFileDialog*) { return S_OK; };
IFACEMETHODIMP OnSelectionChange(IFileDialog*) { return S_OK; };
IFACEMETHODIMP OnShareViolation(IFileDialog*, IShellItem*, FDE_SHAREVIOLATION_RESPONSE*) { return S_OK; };
IFACEMETHODIMP OnOverwrite(IFileDialog*, IShellItem*, FDE_OVERWRITE_RESPONSE*) { return S_OK; };
// This method gets called when the file-type is changed (combo-box selection changes).
// For sample sake, let's react to this event by changing the properties show.
IFACEMETHODIMP OnTypeChange(IFileDialog* pfd)
{
IFileSaveDialog* pfsd;
HRESULT hr = pfd->QueryInterface(&pfsd);
if (SUCCEEDED(hr))
{
UINT uIndex;
hr = pfsd->GetFileTypeIndex(&uIndex); // index of current file-type
if (SUCCEEDED(hr))
{
IPropertyDescriptionList* pdl = NULL;
switch (uIndex)
{
case INDEX_WORDDOC:
// When .doc is selected, let's ask for some arbitrary property, say Title.
hr = PSGetPropertyDescriptionListFromString(L"prop:System.Title", IID_PPV_ARGS(&pdl));
if (SUCCEEDED(hr))
{
// FALSE as second param == do not show default properties.
hr = pfsd->SetCollectedProperties(pdl, FALSE);
pdl->Release();
}
break;
case INDEX_WEBPAGE:
// When .html is selected, let's ask for some other arbitrary property, say Keywords.
hr = PSGetPropertyDescriptionListFromString(L"prop:System.Keywords", IID_PPV_ARGS(&pdl));
if (SUCCEEDED(hr))
{
// FALSE as second param == do not show default properties.
hr = pfsd->SetCollectedProperties(pdl, FALSE);
pdl->Release();
}
break;
case INDEX_TEXTDOC:
// When .txt is selected, let's ask for some other arbitrary property, say Author.
hr = PSGetPropertyDescriptionListFromString(L"prop:System.Author", IID_PPV_ARGS(&pdl));
if (SUCCEEDED(hr))
{
// TRUE as second param == show default properties as well, but show Author property first in list.
hr = pfsd->SetCollectedProperties(pdl, TRUE);
pdl->Release();
}
break;
}
}
pfsd->Release();
}
return hr;
};
// IFileDialogControlEvents methods
// This method gets called when an dialog control item selection happens (radio-button selection. etc).
// For sample sake, let's react to this event by changing the dialog title.
IFACEMETHODIMP OnItemSelected(IFileDialogCustomize* pfdc, DWORD dwIDCtl, DWORD dwIDItem)
{
IFileDialog* pfd = NULL;
HRESULT hr = pfdc->QueryInterface(&pfd);
if (SUCCEEDED(hr))
{
if (dwIDCtl == CONTROL_RADIOBUTTONLIST)
{
switch (dwIDItem)
{
case CONTROL_RADIOBUTTON1:
hr = pfd->SetTitle(L"Longhorn Dialog");
break;
case CONTROL_RADIOBUTTON2:
hr = pfd->SetTitle(L"Vista Dialog");
break;
}
}
pfd->Release();
}
return hr;
};
IFACEMETHODIMP OnButtonClicked(IFileDialogCustomize*, DWORD) { return S_OK; };
IFACEMETHODIMP OnCheckButtonToggled(IFileDialogCustomize*, DWORD, BOOL) { return S_OK; };
IFACEMETHODIMP OnControlActivating(IFileDialogCustomize*, DWORD) { return S_OK; };
CDialogEventHandler() : _cRef(1) { };
private:
~CDialogEventHandler() { };
long _cRef;
};
// Instance creation helper
HRESULT CDialogEventHandler_CreateInstance(REFIID riid, void** ppv)
{
*ppv = NULL;
CDialogEventHandler* pDialogEventHandler = new (std::nothrow) CDialogEventHandler();
HRESULT hr = pDialogEventHandler ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
hr = pDialogEventHandler->QueryInterface(riid, ppv);
pDialogEventHandler->Release();
}
return hr;
}
// This code snippet demonstrates how to work with the common file dialog interface
std::string BasicFileOpen()
{
// CoCreate the File Open Dialog object.
IFileDialog* pfd = NULL;
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr))
{
// Create an event handling object, and hook it up to the dialog.
IFileDialogEvents* pfde = NULL;
hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
if (SUCCEEDED(hr))
{
// Hook up the event handler.
DWORD dwCookie;
hr = pfd->Advise(pfde, &dwCookie);
if (SUCCEEDED(hr))
{
// Set the options on the dialog.
DWORD dwFlags;
// Before setting, always get the options first in order not to override existing options.
hr = pfd->GetOptions(&dwFlags);
if (SUCCEEDED(hr))
{
// In this case, get shell items only for file system items.
hr = pfd->SetOptions(dwFlags | FOS_FORCEFILESYSTEM);
if (SUCCEEDED(hr))
{
// Set the file types to display only. Notice that, this is a 1-based array.
hr = pfd->SetFileTypes(ARRAYSIZE(c_rgSaveTypes), c_rgSaveTypes);
if (SUCCEEDED(hr))
{
// Set the selected file type index to Word Docs for this example.
hr = pfd->SetFileTypeIndex(INDEX_WORDDOC);
if (SUCCEEDED(hr))
{
// Set the default extension to be ".doc" file.
hr = pfd->SetDefaultExtension(L"doc");
if (SUCCEEDED(hr))
{
// Show the dialog
hr = pfd->Show(NULL);
if (SUCCEEDED(hr))
{
// Obtain the result, once the user clicks the 'Open' button.
// The result is an IShellItem object.
IShellItem* psiResult;
hr = pfd->GetResult(&psiResult);
if (SUCCEEDED(hr))
{
// We are just going to print out the name of the file for sample sake.
PWSTR pszFilePath = NULL;
hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
if (SUCCEEDED(hr))
{
TaskDialog(NULL,
NULL,
L"CommonFileDialogApp",
pszFilePath,
NULL,
TDCBF_OK_BUTTON,
TD_INFORMATION_ICON,
NULL);
CoTaskMemFree(pszFilePath);
}
psiResult->Release();
}
}
}
}
}
}
}
// Unhook the event handler.
pfd->Unadvise(dwCookie);
}
pfde->Release();
}
pfd->Release();
}
TCHAR filepath[1024];
if (hr == S_OK)
{
std::stringstream pff;
pff << filepath;
return pff.str();
}
return "";
}
我在从 github 下载的原始文件中更改了他们的代码,它工作得很好。我试图将它复制到另一个项目,但它不起作用(LNK2019 错误)
我想我会为此提供一种 meta-answer:Jerry 怎么知道你需要 link 使用哪些库? 而且,一如既往,答案就在文档中。
首先,让我们看看那些 linker 错误(为了清楚起见,我将它们删减了一些,使用模板通常会导致冗长/难以阅读的错误消息):
Unresolved symbol __imp_TaskDialog referenced in function <irrelevant>
Unresolved symbol __imp_PSGetPropertyDescriptionListFromString referenced in function <irrelevant>
Unresolved symbol QISearch referenced in function <irrelevant>
首先,您可以忽略 __imp_
位。这只是告诉您该函数是从 DLL 导入的。所以这给我们留下了以下未解决的参考:
TaskDialog
PSGetPropertyDescriptionListFromString
QISearch
所以,是时候去谷歌搜索了。
TaskDialog
的文档是 here,如果您向下滚动到页面底部的 'requirements' 部分,您将看到:
Library Comctl32.lib
这就是那个(请注意,这里的大小写无关紧要,我不知道为什么 Microsoft 以如此奇怪的方式记录这些内容)。
同理,我们很容易发现PSGetPropertyDescriptionListFromString
is in Propsys.lib
, and QISearch
在Shlwapi.lib
中。故事结束。
我希望向您展示它是如何完成的。每个 Windows 开发人员都需要了解如何执行此操作以及如何查找和阅读 Microsoft 通常提供的(大量)文档。