2013-10-24 55 views
0

我希望這屬於這個論壇的範疇:MSDN CommonFileDialogModes,改變我的目的

我想使用Windows外殼程序,以允許用戶選擇多個文件讓我的程序做之前(?)給他們幾件事情。爲此,我找到了MSDN樣本 「CommonFileDialogModes」 - http://msdn.microsoft.com/en-us/library/windows/desktop/dd940350%28v=vs.85%29.aspx

在這一大類下的樣品: 類CFileOpenBasketPickerCallback:公共IFileDialogEvents,公共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)不能像繼承。將一個矢量& file_names添加到參數將停止編譯。

那麼我該如何處理呢?我可以爲file_names使用全局變量,但是我正在學習編程的一切都告訴我不要。這將是一個快速解決方案,但我擔心這會鼓勵我在未來變得懶惰。我發現很難閱讀windows代碼,我不想深入研究它的細節。我什至不能找到什麼調用OnFileOk函數,即使我知道它來自兩個基類之一。

我是否真的需要理解所有的庫代碼才能讓這個函數做我想做的事?有沒有更快的方法來解決這個問題?因此,總而言之,如何在不使用全局變量或寫入磁盤的情況下從此繼承函數獲取信息?正如我之前所做的那樣,我沒有太多的把握我正在使用的代碼。爲了將來的參考,我應該如何處理這種情況?我使用C++,並希望儘可能避免c#和c。

一如既往的感謝。

回答

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不是會員,所以你可以消除爭論。

1

微軟似乎漏掉了任何與IFileDialog回調相關的用戶數據,但似乎確實如此。

我假設只需調用GetSelectedItems()一旦對話框返回是你不想出於某種原因而做的事情 - 因爲那顯然是最簡單的解決方案。

從快速瀏覽文檔的方式,您可能能夠從事件回傳數據的方法是使用您傳遞給IFileDialog::Show()(實際上是IModalWindow::Show())的所有者窗口。

在事件處理程序中,您會得到IFileDialog*指針。從此,您可齊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()喜歡的任何數據聯繫起來 - 所以你可以使用它作爲一種機制來從回調中傳回數據。

+0

感謝您的回覆。我試圖按照你的解決方案,但有細節問題。不幸的是,我不熟悉代碼庫。我實際上想出了另一個解決方案,一個我早先應該看到的解決方案。我仍然想了解你的解決方案,所以一旦我發佈了我的當前解決方案,我會寫幾個問題。 – David

+0

好吧,我花了一點時間看你的解決方案。我無法弄清楚如何使用CFileOpenBasketPickerCallback之外的GetSelectedItems()。我也很難理解這部分 - 「你可以QI IOleWindow接口的地址」。我很想看看這是如何工作的,但是我必須閱讀的所有文檔都有點令人頭暈目眩。 – David

+0

@David:查看我發佈的示例代碼! –