我希望这属于这个论坛的范围:
我想使用windows shell(?)允许用户在允许我的程序为他们做一些事情之前选择一些文件。为此,我找到了MSDN示例“CommonFileDialogModes” - http://msdn.microsoft.com/en-us/library/windows/desktop/dd940350%28v=vs.85%29.aspx
在此课程下的示例中: class CFileOpenBasketPickerCallback:public IFileDialogEvents,public IFileDialogControlEvents
他们有这个功能:
// IFileDialogEvents
IFACEMETHODIMP OnFileOk(IFileDialog *pfd)
{
// if this button is in the "Add" mode then do this, otherwise return S_OK
IFileOpenDialog *pfod;
HRESULT hr = pfd->QueryInterface(IID_PPV_ARGS(&pfod));
if (SUCCEEDED(hr))
{
IShellItemArray *psia;
hr = pfod->GetSelectedItems(&psia);
if (SUCCEEDED(hr))
{
ReportSelectedItems(pfd, psia);
psia->Release();
}
pfod->Release();
}
return S_FALSE; // S_FALSE keeps the dialog up; return S_OK to allow it to dismiss.
}
调用:
void ReportSelectedItems(IUnknown *punkSite, IShellItemArray *psia)
{
DWORD cItems;
HRESULT hr = psia->GetCount(&cItems);
for (DWORD i = 0; SUCCEEDED(hr) && (i < cItems); i++)
{
IShellItem *psi;
hr = psia->GetItemAt(i, &psi);
if (SUCCEEDED(hr))
{
PWSTR pszName;
hr = GetIDListName(psi, &pszName);
// .. I've cut some of this out for the example
CoTaskMemFree(pszName);
}
psi->Release();
}
}
}
现在我知道pszName包含所选文件的名称。所以我可以添加一些额外的代码将其写入磁盘。这很好。但我不想把它写到磁盘上。我想将它传递给调用它的原始函数。可以更改ReportSelectedItems的参数,但IFACEMETHODIMP OnFileOk(IFileDialog * pfd)不能继承。添加矢量&amp;参数的file_names将停止编译。
那我应该怎么处理呢?我可以为file_names使用全局变量,但是我正在学习的关于编程的一切都告诉我不要。这将是一个快速解决方案,但我担心这会鼓励我将来变得懒惰。我发现很难阅读windows代码,我真的不想深入研究它的细节。我甚至无法找到调用OnFileOk函数的内容,即使我知道它来自两个基类之一。
我是否真的需要努力理解所有的库代码,只是为了让这个函数做我想做的事情?有没有更快的方法来解决这个问题?
总而言之,如何在不使用全局变量或写入磁盘的情况下从此继承函数获取信息?正如我之前所说,我对我正在使用的代码没有多少把握。为了将来参考,我应该如何处理这种情况?我使用c ++并希望尽可能避免使用c#和c。
一如既往地谢谢。
答案 0 :(得分:1)
微软似乎忽略了与IFileDialog
回调相关的任何类型的用户数据,但似乎确实如此。
我假设在对话框返回后简单地调用GetSelectedItems()
是出于某种原因你不想做的事情 - 因为这显然是最简单的解决方案。
通过快速查看文档,您可以通过一种方式从事件回调中传回数据,使用您传递给IFileDialog::Show()
的所有者窗口(实际上是IModalWindow::Show()
)。< / p>
在事件处理程序中,您将获得IFileDialog*
指针。从这里,你可以QI IOleWindow
接口的地址,它将为你提供对话框的窗口:
IFACEMETHODIMP OnFileOk(IFileDialog *pfd)
{
CComPtr<IOleWindow> pWindow;
if (SUCCEEDED(pfd->QueryInterface(IID_IOleWindow, reinterpret_cast<void**>(&pWindow))))
{
HWND hwndDlg;
if (SUCCEEDED(pWindow->GetWindow(&hwndDlg)))
{
HWND hwndOwner;
if (hwndOwner = GetWindow(hwndDlg, GW_OWNER))
{
// hwndOwner is the owner window of the dialog
}
}
}
// more code
}
现在假设hwndOwner
是您自己的窗口,您可以使用SetProp()
/ GetProp()
将您喜欢的任何数据与它相关联 - 因此您可以将此作为一种机制将数据传回来自回调。
答案 1 :(得分:0)
一个简单的解决方案是在继承的类中添加成员数据,并从构造函数中链接它:
class CFileOpenBasketPickerCallback : public IFileDialogEvents, public IFileDialogControlEvents
{
public:
CFileOpenBasketPickerCallback(vector<wstring>& files) : files_(files)
{
}
// functions
private:
vector<wstring>& files_;
};
构造对象时
vector<std::wstring> files
CFileOpenBasketPickerCallback foacb(files);
在IFACEMETHODIMP OnFileOk(IFileDialog * pfd)
ReportSelectedItems(pfd, psia, files_);
ReportSelectedItems不是成员,因此您可以更改参数。