C ++/CLI/VC. Net to implement openfiledialog customization, so that he can select folders

Source: Internet
Author: User
1. Cause
Some time ago, you had to use openfiledialog to select a folder. There is a C # method on Google, which is relatively simple. You only need to set filter = messy symbols so that all files cannot be displayed. But this is always a bit uncomfortable. It reminds me of the VC openfiledialog customization created in the MFC mode in the past. You need to use the resource file (because the system function requires you to provide your template ID ). C # can also be implemented, but the res file must be included, this is very troublesome, you can see here: http://blog.csdn.net/norsd/article/details/8840761, so consider generating a C ++/CLI/vc.net as the language. net class library

2. Principles

The principle is very simple, as in the past:
: Getopenfilename (& stofn)

Getopenfilename is actually a macro, which is defined as getopenfilenamea and getopenfilenamew according to the environment.

Then stofn is a structure type: openfilename

For customization, we must set: openfilename: lptemplatename = id_dialog. This is strange. msdn requires a string, but we must pass a number (resource number ), specific reasons I have seen in the past, a black book called: MFC internal technology (http://book.douban.com/subject/1000127/) has written a sentence.

Openfilename: lpfnhook: This is actually the messageproc of the dialog. If a message is returned to true, it indicates that the message is customized and false indicates that the message is processed by the system by default.

3. header file:

# Pragma once # include <windows. h> # include <commdlg. h> # include <commctrl. h ># include <vector> # pragma comment (Lib, "comdlg32.lib") # pragma comment (Lib, "user32.lib") # pragma comment (Lib, "comctl32.lib ") # include <vcclr. h> # include "resource. H "using namespace STD; using namespace system: Windows: forms; using namespace system: collections :: generic; using namespace system: IO; using namespace System: text; using namespace system: runtime: interopservices; namespace norlib {namespace controls {Public Delegate uint_ptr values (hwnd hdlg, uint umsg, wparam, lparam ); public ref class openfiledialogex: commondialog {public: openfiledialogex (string ^ arg_initpath) {initpath = arg_initpath; Limit ^ fp = gcnew convert (this, & norlib: Controls: openfiledialog Ex: ofnhookprocoldstyle); _ gchofnhookprocoldstyle = gchandle: alloc (FP); _ inrofnhookprocoldstyle = MARSHAL: getfunctionpointerfordelegate (FP );}~ Openfiledialogex () {_ gchofnhookprocoldstyle. free ();} public: // A externally passed string property string ^ initpath; property string ^ initfolderpath; property string ^ title; property string ^ filename; property array <string ^> ^ filenames; property bool showreadonly; property bool acceptfiles; property bool multiselect; property string ^ Foldername; // For instance: "C: \ mydir1 \ mydir2 "public: Virtual void reset () override {Foldername = Nullptr; Title = nullptr; acceptfiles = true;} virtual bool rundialog (intptr hwndowner) override {# pragma Region Analysis region = initpath; filename = l ""; if (IO :: file: exists (initpath) {initfolderpath = IO: Path: getdirectoryname (initpath); If (acceptfiles) {filename = IO: Path :: getfilename (initpath) ;}# Pragma endregionpin_ptr <const wchar_t> pintitle = ptrtostringchars (title); pin _ PTR <const wchar_t> pininitfolderpath = partition (initfolderpath); pin_ptr <const wchar_t> pinfilename = partition (filename); tchar chsfilename [filemaxlen];: memset (chsfilename, 0, sizeof (chsfilename);: wcscpy (chsfilename, pinfilename); openfilename stofn = {0}; stofn. lstructsize = sizeof (openfilename); stofn. hwndowner = (hwnd) hwndowner. toint64 (); stofn. nmaxfile = filemaxlen; stofn. lpstrfile = (Pwstr) & chsfilename; stofn. lpstrinitialdir = pininitfolderpath; If (! Acceptfiles) {string ^ STR = string: Format ("Folders \ 0 *. {0}-{1} \ 0 \ 0 ", guid: newguid (). tostring ("N"), guid: newguid (). tostring ("N"); pin_ptr <const wchar_t> pcwstr = ptrtostringchars (STR); stofn. lpstrfilter = pcwstr;} else {stofn. lpstrfilter = NULL;} stofn. nmaxcustfilter = 0; stofn. nfilterindex = 0; stofn. nmaxfile = filemaxlen; stofn. nmaxfiletitle = 0; stofn. lpstrtitle = pintitle; stofn. lpfnhook = (lpofnhookpr OC) _ inrofnhookprocoldstyle. topointer (); stofn. lptemplatename = (pcwstr) idd_customopendialog; stofn. hinstance = (hinstance) (MARSHAL: gethinstance (this-> GetType ()-> module ). toint64 (); stofn. flags = ofn_dontaddtorecent | ofn_enablehook | ofn_enablesizing | ofn_notestfilecreate | ofn_explorer | ofn_filemustexist | ofn_pathmustexist | optional | ofn_enabletemplate | (multiselect? Ofn_allowmultiselect: 0) | (showreadonly? 0: ofn_hidereadonly);: getopenfilename (& stofn); int exterrpr =: commdlgextendederror (); If (exterrpr! = 0) {string ^ strerr = string: Format (L "openfilename creation dialog box failed \ r \ n error: {0}", exterrpr); System: Windows :: forms: MessageBox: Show (strerr);} filename = nullptr; filenames = nullptr; If (_ bresult) {pwstr pw1st = chsfilename; filename = gcnew string (pw1st ); /// the returned value of multiselect is /// 1. folder path D:/test/DIR // 2. file Name 1 test1.txt // 3. file name 2 test2.txtif (multiselect) {vector <pwstr> vtstr; pwstr pwfilename = pw1st; int nindex = wcsl En (pwfilename) + 1; int nmaxindex = filemaxlen; while (nindex <nmaxindex) {pwfilename = chsfilename + nindex; If (pwfilename [0] = NULL) break; vtstr. push_back (pwfilename); nindex + = wcslen (pwfilename) + 1;} int ncount = vtstr. size (); string ^ strfolder = gcnew string (pw1st) + "\"; filenames = gcnew array <string ^> (ncount); vector <pwstr >:: iterator P; // point to the first element of the container P = vtstr. begin (); nindex = 0; For (; P! = Vtstr. End (); P ++) {filenames [nindex ++] = strfolder + (gcnew string (* p);} filename = filenames-> length> 0? Filenames [0]: Filename;} return _ bresult;} protected: Virtual intptr hookproc (intptr hwnd, int MSG, intptr wparam, intptr lparam) override {Throw "impo! ";} Uint_ptr ofnhookprocoldstyle (hwnd hdlg, uint umsg, wparam, lparam); Private: void initdialog (hwnd); void _ resizecustomecontrol (); // set the Custom button location void _ onclickselect (hwnd arg_hwnd, uint arg_umessage, wparam arg_wparam, lparam arg_lparam); int processpolicymessage (hwnd, ofpolicy & policydata ); /// tool function PRIVATE: String ^ _ getdlgitemtext_t (uint arg_ucontrolid) {hwnd hitem = _ getdlgitem_t (arg_ucontrolid); Return _ getwindowtext_t (hitem );} string ^ _ getwindowtext_t (hwnd) {tchar chstext [2048] = {0};: getwindowtext (hwnd, chstext, sizeof (chstext)/sizeof (tchar )); return gcnew string (chstext);} void _ enablecontrol_t (uint arg_ucontrolid, bool arg_benable) {hwnd hfiltercombo = _ lower (arg_ucontrolid);: enablewindow (lower, arg_benable );} void _ hidecontrol_t (uint arg_ucontrolid) {sendmessage (_ hdlg, cdm_hidecontrol, arg_ucontrolid, 0);} void _ setcontroltext_t (uint arg_ucontrolid, lpcwstr arg_pcwtext) {hwnd hcontrol = _ lower (arg_ucontrolid);: setwindowtext (hcontrol, arg_pcwtext);} windowplacement _ lower (uint arg_ucontrolid) {windowplacement stplacement; hwnd hcontrol = _ lower (arg_ucontrolid );: getwindowplacement (hcontrol, & stplacement); Return stplacement;} void _ increment (uint arg_ucontrolid, windowplacement & arg_stplacement) {hwnd hcontrol = _ increment (arg_ucontrolid); setwindowplacement (hcontrol, & arg_stplacement);} hwnd _ getdlgitem_t (uint arg_ucontrolid) {hwnd = getdlgitem (_ hdlg, arg_ucontrolid); If (hwnd = NULL) {return getdlgitem (_ hthis, arg_ucontrolid);} return hwnd;} uint_ptr _ getfont_t (uint arg_ucontrolid) {hwnd = _ getdlgitem_t (arg_ucontrolid); Return sendmessage (hwnd, wm_getfont );} void _ setfont_t (uint arg_ucontrolid, uint_ptr arg_hfont) {hwnd = _ random (arg_ucontrolid); sendmessage (hwnd, wm_setfont, arg_hfont, 0);} string ^ _ random () {tchar chstext [2048]; commdlg_opensave_getfolderpath (_ hdlg, chstext, sizeof (chstext)/sizeof (tchar); Return gcnew string (chstext);} PRIVATE: /// two-layer structure: initdialoghwnd _ hthis; hwnd _ hdlg; gchandle _ HANDLE; intptr _ inrofnhookprocoldstyle; bool _ bresult; static const int filemaxlen = 2048 ;};}}

Implementation file:

// This is the main DLL file. # include "stdafx. H "# include" controls. openfiledialogex. H "Void norlib: Controls: Authorization: _ onclickselect (hwnd arg_hwnd, uint arg_umessage, wparam logs, lparam logs) {If (acceptfiles) {sendmessage (arg_hwnd, arg_umessage, arg_wparam, arg_lparam);} else {// process folderstring ^ strfolderpath = _ getfolderpath_t (); // absolute path if (IO: Path: ispathrooted (strfolderpath )) {If (directory: exists (strfolderpath) {Foldername = strfolderpath; _ bresult = true;: sendmessage (_ hdlg, wm_close, 0, 0 );}} //// relative path // else if (! String: isnullorempty (m_currentfolder) & strfilenamecombo! = "") // {// Var combined = system: IO: Path: Combine (m_currentfolder, currenttext); // If (directory. exists (combined) // {// the contents of the text box are a relative path, that points to a // an existing Directory. we interpret the users intent to mean that they wanted // to select the existing path. // m_usecurspondir = true; // m_currentfolder = combined; // hparent. sendmessage (interoputil. wm_close, 0, 0); // break; //} // The user has not selected an existing folder. /// so we translate a click of our "select" button into the OK button and forward the request to the // open file dialog. // hparent. sendmessage // (// interoputil. wm_command, // (interoputil. bn_clicked <16) | interoputil. idok, // unchecked (uint) hparent. getdlgitem (interoputil. idok) //);} int norlib: Controls: openfiledialogex: processnot Ifymessage (hwnd, ofpolicy & policydata) {Switch (policydata. HDR. code) {Case cdn_folderchange: {// string ^ newfolder = gettextfromcommondialog (: getparent (hwnd), cdm_getfolderpath); // If (m_currentfolder! = Nullptr & newfolder! = Nullptr & newfolder-> pathcontains (m_currentfolder) // {// m_suppressselectionchange = true; //} // m_currentfolder = newfolder; // var filenamecombo = hwnd. getparent (). assumenonzero (). getdlgitem (interoputil. id_filenamecombo ). assumenonzero (); // If (m_hasdirchangefired) // {// filenamecombo. setwindowtextw (""); // m_hasdirchangefired = true; break;} case cdn_fileok: {If (! Acceptfiles) {return 1;} break;} case cdn_initdone: {hwnd hparent =: getparent (hwnd); hwnd hfile =: getdlgitem (hparent, id_filenametextcombo );:: setfocus (hfile); break;} return 0;} void norlib: Controls: openfiledialogex: _ resizecustomecontrol () {windowplacement loccancel = _ getplacement_t (idcancel ); windowplacement locselect = _ getplacement_t (id_select); locselect. rcnormalposition. right = _ getplacement_t (I D_filenametextcombo ). rcnormalposition. right; _ setplacement_t (id_custom_cancel, loccancel); rect & rccancel = loccancel. rcnormalposition; rect & rc = locselect. rcnormalposition; rc = rccancel; RC. right = RC. left-10; RC. left = RC. right-(rccancel. right-rcCancel.left); _ setplacement_t (id_select, locselect); hwnd hselectbtn = _ getdlgitem_t (id_select); hwnd hcacelbtn = _ getdlgitem_t (id_custom_cancel ); (Hselectbtn, null, true); invalidaterect (hcacelbtn, null, true);} void norlib: Controls: openfiledialogex: initdialog (hwnd) {_ hdlg = :: getparent (hwnd); _ hthis = hwnd; _ enablecontrol_t (id_filtercombo, false); _ hidecontrol_t (id_filtercombo); _ hidecontrol_t (id_filterlabel ); // We don't want the accelerator keys for the OK and cancel buttons to work, because // they are not shown on the dialog. however, we sti Ll want the buttons enabled // so that "ESC" and "enter" have the behavior they used. so, we just // clear out their text instead. _ setcontroltext_t (idok, l ""); _ setcontroltext_t (idcancel, l ""); // find our button controls _ setfont_t (id_select, _ getfont_t (idok )); _ setfont_t (id_custom_cancel, _ getfont_t (idcancel); windowplacement cancelloc = _ getplacement_t (idcancel); // hide the OK and cancel buttons_h Idecontrol_t (idcancel); _ hidecontrol_t (idok); // expand the file name combo to take up the space left by the OK and cancel buttons. windowplacement filenameloc = _ getplacement_t (id_filenametextcombo); windowplacement okbuttonloc = _ getplacement_t (idok); filenameloc. rcnormalposition. right = okbuttonloc. rcnormalposition. right; _ setplacement_t (id_filenametextcombo, filenameloc); If (! Acceptfiles) {_ setcontroltext_t (delimiter, l "folder name:");} windowplacement parentloc; getwindowplacement (_ hdlg, & parentloc); // subtract the height of the missing cancel buttonparentloc. rcnormalposition. bottom-= (cancelloc. rcnormalposition. bottom-cancelloc. rcnormalposition. top); setwindowplacement (_ hdlg, & parentloc); // move the select and custom cancel buttons to the right hand side of the win Dow: windowplacement selectloc = _ blank (id_select); windowplacement customcancelloc = _ getplacement_t (id_custom_cancel); windowplacement ctrlloc; getwindowplacement (hwnd, & ctrlloc); ctrlloc. rcnormalposition. right = filenameloc. rcnormalposition. right;} uint_ptr norlib: Controls: openfiledialogex: ofnhookprocoldstyle (hwnd hdlg, uint umsg, wparam, lparam) {Switch (umsg G: {initdialog (hdlg); break;} case wm_notify: {ofnotify * pnotifydata = (ofnotify *) lparam; uint_ptr Results = processpolicymessage (hdlg, * pnotifydata); If! {// Http://msdn.microsoft.com/ZH-CN/library/windows/desktop/ms633591 (V = vs.85 ). aspx //: setwindowlong (hdlg, dwl_msgresult, results); // 64bit http://sourceforge.net/p/bochs/bugs/1250/::SetWindowLongPtr (hdlg, dwlp_msgresult, results ); // if you use setwindowlongptr with the dwlp_msgresult index to set the return value for a message processed by a dialog box procedure, // the dialog box procedure shoshould return true directly afterward. // otherwise, if you call any function that results in your dialog box procedure messages ing a window message, // The nested window message cocould overwrite the return value you set by using dwlp_msgresult.return true ;} break;} case wm_size: {_ resizecustomecontrol (); break;} case wm_command: {hwnd hparent = getparent (hdlg); Word Code = hiword (wparam ); word ID = loword (wparam); If (code = bn_clicked) {Switch (ID) {Case id_custom_cancel: {// The user clicked our custom cancel button. close the dialog. sendmessage (hparent, wm_close, 0, 0); break;} case id_select: {_ onclickselect (hparent, wm_command, idok, null); break ;}} break ;}} return 0 ;}

App. RC file

// Microsoft Visual C++ generated resource script.//#include "resource.h"#define APSTUDIO_READONLY_SYMBOLS///////////////////////////////////////////////////////////////////////////////// Generated from the TEXTINCLUDE 2 resource.//#include "afxres.h"/////////////////////////////////////////////////////////////////////////////#undef APSTUDIO_READONLY_SYMBOLS/////////////////////////////////////////////////////////////////////////////// English (United States) resources#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US///////////////////////////////////////////////////////////////////////////////// Icon//// Icon with lowest ID value placed first to ensure application icon// remains consistent on all systems.1                       ICON                    "app.ico"#ifdef APSTUDIO_INVOKED///////////////////////////////////////////////////////////////////////////////// TEXTINCLUDE//1 TEXTINCLUDE BEGIN    "resource.h\0"    "\0"END2 TEXTINCLUDE BEGIN    "#include ""afxres.h""\r\n"    "\0"END3 TEXTINCLUDE BEGIN    "\0"END#endif    // APSTUDIO_INVOKED///////////////////////////////////////////////////////////////////////////////// Dialog//IDD_CustomOpenDialog DIALOGEX 0, 0, 177, 17STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_TABSTOPFONT 8, "MS Sans Serif", 0, 0, 0x0BEGIN    DEFPUSHBUTTON   "&Select",ID_SELECT,3,0,50,15    PUSHBUTTON      "&Cancel",ID_CUSTOM_CANCEL,59,0,50,15END///////////////////////////////////////////////////////////////////////////////// DESIGNINFO//#ifdef APSTUDIO_INVOKEDGUIDELINES DESIGNINFOBEGIN    IDD_CustomOpenDialog, DIALOG    BEGIN        RIGHTMARGIN, 174    ENDEND#endif    // APSTUDIO_INVOKED#endif    // English (United States) resources/////////////////////////////////////////////////////////////////////////////

Resource. h file

//{{NO_DEPENDENCIES}}// Microsoft Visual C++ generated include file.// Used by app.rc//#define IDD_CustomOpenDialog            101#define IDI_ICON1                       105#define ID_SELECT                       1001#define ID_CUSTOM_CANCEL                1002// Next default values for new objects// #ifdef APSTUDIO_INVOKED#ifndef APSTUDIO_READONLY_SYMBOLS#define _APS_NEXT_RESOURCE_VALUE        102#define _APS_NEXT_COMMAND_VALUE         40001#define _APS_NEXT_CONTROL_VALUE         1000#define _APS_NEXT_SYMED_VALUE           101#endif#endif#define IDOK  1#define IDCANCEL  2//control aliases that actually make sense....#define ID_FilterCombo  0x0470#define ID_FilterLabel  0x0441#define ID_FileNameLabel 0x0442#define ID_FileNameTextBox 0x0480#define ID_FileNameTextCombo 0x047c#define ID_FileList 0x0461

Some technical details in it are very simple. It is nothing more than hiding the original two OK and cancel buttons, and then replacing our own buttons. If you don't understand them, you can ask.

This is the source code.

After compilation, it can be used on. NET.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.