MSDN CommonFileDialogModes,改变我的目的

时间:2013-10-24 06:52:35

标签: c++ windows winapi win32gui

我希望这属于这个论坛的范围:

我想使用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。

一如既往地谢谢。

2 个答案:

答案 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不是成员,因此您可以更改参数。