ifile:IFileDialog使用指南 2024-03-30 10:48:26 0 0 IFileDialog的使用方法 作者:收割者 Prerequisite: C++编程者,了解或是熟悉COM(组件对象模型)。 打开文件对话框或是另存为对话框,大家都很熟悉。在过去(Vista之前),在win32中是使用GetOpenFileName或是GetSaveFileName API来实现,在MFC中使用CFileDialog类来实现。现在在Vista之后的系统,有了一种新的实现方法,就是今天要讲的,通过IFileDialog接口,这是一个COM接口,从它继承之后有两个接口,一个是IFileOpenDialog,另外一个IFileSaveDialog。这两个接口分别实现了打开文件对话框和另存为文件对话框。如下图: typedef struct _COMDLG_FILTERSPEC { LPCWSTR pszName; LPCWSTR pszSpec; } COMDLG_FILTERSPEC; 第一个成员是文件类型,第二个成员是文件的扩展名。例如: COMDLG_FILTERSPEC rgSpec[] = { { L"JPG", L"*.jpg;*.jpeg" }, { L"BMP", L"*.bmp" }, { L"All", L"*.*" }, }; 设置好了之后,调用IFileDialog的方法: HRESULT SetFileTypes(UINT cFileTypes, constCOMDLG_FILTERSPEC *rgFilterSpec); 这个方法的第一个参数后面那个参数中元素的个数,如在这里,是3个,因此就是3: hr=pfd->SetFileTypes(3,rgSpec); 设置文件类型索引: hr = pfd->SetFileTypeIndex(1); 通过设置这个,就可以设置默认选中的文件类型项目上面。 设置默认扩展名: 这个功能主要是用于在另存为对话框中,将这里设置的默认扩展名附到将要保存的文件的后面。 hr=pfd->SetDefaultExtension(L"jpg"); 显示对话框: 如果设置完毕之后,就可以显示对话框,调用Show方法,这个方法是IModalWindow接口的方法,IFileDialog继承于它,因此可以调用。 hr=pfd->Show(this->m_hWnd);///显示打开文件对话框 这个时候,对话框显示出来,根据返回值hr就可以判断用户是点击去了取消还是选择了一个文件打开,根据不同的用户选择做出反应。如果用户点击了取消,那么就释放所有的接口指针并返回。如果用户点击了打开,就可以继续调用GetResult方法,获取用户选择的项目: hr=pfd->GetResult(&pShellItem);获取用户选择对象(文件) 这个方法直接就可以获取文件的IShellItem接口指针。通过这个接口指针,就可以很方便的实现如获取上一级目录的IShellItem指针,实现枚举,获取文件名,还是获取完整路径(相对于桌面路径)等等,因为在windows中要对文件夹,或是文件做各种操作,是通过获取它们的IShellItem接口指针实现的,过去我们只能获取打开文件的路径,而要获取被选中文件的IShellItem还需要我们自己编写代码实现。现在就可以直接获取了。如果是设置了可以选择多个文件,可以使用QueryInterface获取IFileOpenDialog接口,然后调用GetResults获取IShellItemArray指针,通过它就可以获取各个被选中文件的IShellItem的接口指针。 获取文件名或路径: LPWSTR filePath; LPWSTR fileName; // hr=pShellItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&filePath);//获取文件的完整路径 hr=pShellItem->GetDisplayName(SIGDN_NORMALDISPLAY,&fileName);///获取文件名 调用IShellItem接口的GetDisplayName方法就可以获取你想要的信息,第一个参数是一个枚举值,通过设置不同的值,返回的接口就不同,这里我分别设置获取所选择文件的完整路径和文件名。另外,需要注意的是,这里的输入参数是一个指针,但是不用我们分配内存,由COM对象为我们分配,这样很方便了,但是需要我们自己来释放,而且必须使用COM的内存管理方式来管理COM分配的内存,在COM中,分配内存使用CoTaskMemAlloc,释放类存使用CoTaskMemFree。另外补充一下,对于初学COM的同学来说,不明白为什么随处可见参数是双指针的情况,例如,这里也是,因为要实现传递指针的地址,我们知道,传递一个变量的地址用指针,现在要传递指针的地址,就需要用双指针。 CoTaskMemFree(filePath);//销毁com分配的内存 CoTaskMemFree(fileName);// 释放所有的接口指针: SafeRelease(&pfd); SafeRelease(&pShellItem); /// 这样就完成了IFileDialog接口指针的基本实现。 2获取IFileDialog对话框上的事件 在过去的使用打开文件对话框或是另存为对话框是没有办法实现的。例如:用户选择的项目发生变化,选择的对话框发生变化等等,用户的每个操作都可以捕捉到。要实现这个功能,需要我们重写IFileDialogEvents接口,重写这个接口和我们在编写COM组件时实现接口的过程是一样一样的。至于如何实现COM接口,这里不做叙述。我这里做的,可以到我的源码中查看。实现完了接口之后,我需要一个函数来初始化这个一个对象,因此我在实现的接口类中定义了一个静态的函数CreateInstance来初始化对象并获取指定的接口指针。 static HRESULT CreateInstance(REFIID iid,void**ppObject); ///建立对象 HRESULT CFileDialogEvent::CreateInstance(REFIID iid,void**ppObject) { if(ppObject==NULL) { return E_POINTER; } CFileDialogEvent *fdf=new (std::nothrow)CFileDialogEvent; if(fdf==NULL) { return E_FAIL; } fdf->QueryInterface(iid,ppObject); fdf->Release(); return S_OK; } 接着,调用IFileDialog接口的Advise方法将这个初始化的对象指针与其绑定: hr=CFileDialogEvent::CreateInstance(IID_IFileDialogEvents,(void**)&pfde);///创建事件处理对象 hr=pfd->Advise(pfde,&dwCookie);///将事件处理对象与IFileDialog绑定 dwCookie是返回回来的一个标示符,当IFileDialog接口销毁之前,调用UnAdvise方法解除绑定,就用这个标识符来解除之前的绑定。 pfd->Unadvise(dwCookie); 这样之后,就可以完成对对话框事件的捕捉功能 3自定义对话框的外观 过去要自定义打开文件对话框模板,需要使用内存模板,这是一个很费力的工作。现在就很容易了,通过使用IFileDialogCustomize接口,通过在IFileDialog接口上调用QueryInterface方法,就可以获取这个接口,通过这个接口,可以添加按钮,下拉列表,编辑框等等窗口元素到打开文件或是文件另存为对话框中。例如,我在这里添加了两个按钮: hr=pfd->QueryInterface(IID_PPV_ARGS(&pfdc)); if(FAILED(hr)) { goto End; } hr=pfdc->StartVisualGroup(ID_GROUP,L"收割者"); if(FAILED(hr)) { goto End; } hr=pfdc->AddPushButton(ID_BUTTONA,L"收割者的按钮A"); if(FAILED(hr)) { goto End; } hr=pfdc->AddPushButton(ID_BUTTONB,L"收割者的按钮B"); if(FAILED(hr)) { goto End; } hr=pfdc->EndVisualGroup(); 为了能够响应添加到对话框上按钮的事件,我们还需要实现一个接口IFileDialogControlEvents,实现这个接口和实现IFileDialogEvents一样,而且是在同一个对象上。但是IFileDialogControlEvents接口不需要我们传递给IFileDialog,因为我们之前调用Advise将IFileDialogEvents接口指针与IFileDialog的对象绑定,由于两个事件接口指针都在同一个对象上实现的,在内部,当我们点击按钮或是别的控件的时候,就会自动调用实现这两个事件接口的类的QueryInterface方法,获取IFileDialogControlEvents指针,然后在内部调用相关的方法,例如,在这里我在添加了两个按钮,我响应这两个按钮的点击事件: HRESULT CFileDialogEvent::OnButtonClicked(IFileDialogCustomize *pfdc,DWORD dwIDCtl) { if(dwIDCtl==1) { AfxMessageBox(L"我是收割者A"); } else if(dwIDCtl==2) { AfxMessageBox(L"我是收割者B"); } return S_OK; } 下面是效果图: 这里是以打开文件对话框为例,如果要实现另外为对话框,使用CLSID_FileSaveDialog来获取另存为对话框的IFileDialog接口指针,来实现另存为对话框。 本文代码 http://download.csdn.net/detail/xinzhiyounizhiyouni/7114295 其他推荐阅读地址:http://www.panshy.com/article/Sort_Desktop/UI/2014-03-23/2470.php 收藏(0)