MFC记住上次路径---遇到的一些问题

今天完成一个需求,就是记住用户选择的文件路径,先是熟悉代码,然后在网上找解决方法,一开始感觉没什么,网上的方法差不多,应该很容易做出来,结果真是卡了一半天,到晚上自己才慢慢的搞清楚了。

遇到的问题真不少,记录一下好多细节,真是不写不知道。

1.基本方法

http://blog.csdn.net/shuilan0066/article/details/7302904

http://www.cnblogs.com/Hisin/archive/2012/02/27/2370614.html

这两篇是比较清楚的。

先认识了

SHBrowseForFolder打开文件夹时,每次都是从根目录打开。要记住上次的路径或者设置默认路径,需要写个回掉函数。

CFileDialog会自动记住上次路径

int CALLBACK BrowseCallBackFun(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
    switch(uMsg)
    {
    case BFFM_INITIALIZED:  //选择文件夹对话框初始化
     //设置默认路径为lpData即‘D:\‘
        ::SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
        //在STATUSTEXT区域显示当前路径
        ::SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, lpData);
        //设置选择文件夹对话框的标题
        ::SetWindowText(hwnd, TEXT("请先设置个工作目录"));
        break;
    case BFFM_SELCHANGED:   //选择文件夹变更时
        {
            TCHAR pszPath[MAX_PATH];
            //获取当前选择路径
            SHGetPathFromIDList((LPCITEMIDLIST)lParam, pszPath);
            //在STATUSTEXT区域显示当前路径
            ::SendMessage(hwnd, BFFM_SETSTATUSTEXT, TRUE, (LPARAM)pszPath);
        }
        break;
    }
    return 0;
}
  

回掉函数首先搞清楚参数的意义

2.SHBrowseForFolder函数

打开文件目录对话框,我找到的方法就是使用SHBrowseForFolder函数,这个函数的原型是LPITEMIDLIST SHBrowseForFolder(LPBROWSEINFO lpbi)。函数很简单,就一个返回值和一个参数。参数简单罗列如下

typedef struct _browseinfo {

HWND hwndOwner;            // 父窗口句柄

LPCITEMIDLIST pidlRoot;    // 要显示的文件目录对话框的根(Root)

LPTSTR pszDisplayName;     // 保存被选取的文件夹路径的缓冲区

LPCTSTR lpszTitle;         // 显示位于对话框左上部的标题

UINT ulFlags;              // 指定对话框的外观和功能的标志

BFFCALLBACK lpfn;          // 处理事件的回调函数

LPARAM lParam;             // 应用程序传给回调函数的参数

int iImage;                // 文件夹对话框的图片索引

} BROWSEINFO, *PBROWSEINFO, *LPBROWSEINFO

一般而言父窗口句柄(hwndOwner)和根(pidlRoot)设置为Null就可以了,pszDisplayName设定一块MAX_PATH大小的缓冲区,跟显示相关的参数就是对话框提示标题(lpszTitle)、对话框样式(ulFlags)、设定对话框的缺省路径的操作(lpfn和lParam)以及对话框任务栏上显示的图标(iImage)。

由于返回值LPITEMIDLIST是一个指向ITEMIDLIST的指针,这个ITEMIDLIST涉及到Windows Shell中关于管理诸如文件、网络上的计算机、控制面板程序、回收站等等对象的知识点,Windows Shell为了识别具体的每一个对象,就使用了ITEMID来唯一识别和区分,而ITEMIDLIST就是一个完整的对象路径。显然这个函数可以用来浏览非文件对象,比如局域网内的电脑等等,在这里这个LPITEMIDLIST返回的对象路径是一个文件夹的路径,Windows提供了一个函数BOOL SHGetPathFromIDList(LPCITEMIDLIST pidl, LPSTR pszPath)来实现从对象路径转化为文件夹路径。

弄清楚每个参数的意义,然后才能按需求设定初值。先太盲目了,只知道套别人的,根本就没有理解。

                LPCITEMIDLIST pidl = NULL;
                BROWSEINFO bi;
                bi.hwndOwner = AfxGetMainWnd()->GetSafeHwnd();
                bi.pidlRoot = NULL;
                bi.pszDisplayName = folderName;
                bi.lpszTitle = _T("请选择用于保存的文件夹");
                bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT;;
                bi.lpfn = BrowseCallbackProc;    //回调函数
                bi.iImage = 0;
                bi.lParam = long(&szPath);  //设置默认路径,传给回掉函数的参数

                pidl = SHBrowseForFolder(&bi);
                if (pidl)
                {
                    SHGetPathFromIDList(pidl, szPath);
                 }

3.回掉函数

     先看别人说设置全局的静态变量,然后设置静态变量和静态函数,开始编译通不过,要搞清楚类里面怎么写这种特殊的静态变量和函数。

      静态变量初始化,在cpp中,回掉函数的定义.h中static,cpp不需要了。

     感觉回掉函数只是发送了一些消息,根本就没有什么其他的用处,然后有人用lpData设置默认路径,我也试过吧,没有成功。

4.记住路径

在软件开启的时候,设置全局变量,每个更新默认的路径即可,但是重新开启软件的时候,采用先写入注册表中,然后再读注册表的路径,这样就解决了问题。也可以写到ini文件中。

5.CString与TCHAR数组 相互转换

TCHAR数组转到CString很简单:使用CString的Format就行。

TCHAR m_buf[100] = _T("Hello");

CString str;

str.Format(L"%s",m_buf);

现在就来CString转为TCHAR数组,这个就有点麻烦了。因为网上有很多的解决方案,但是都不怎么理想。我们使用_tcscpy()宏。

CString str = L"sssssss";

TCHAR m_buf[20];

_tcscpy(m_buf, str);  //类型之间的转换真麻烦,知道定义这个宏的好处了。

自己找了半天,这个方法很有效!用memcpy,strcpy都不行。。。

TCHAR szDefaultDir[MAX_PATH];
                CString strDef(_T("E:\\"));
                memcpy(szDefaultDir, strDef.GetBuffer(strDef.GetLength() * 2), strDef.GetLength() * 2);
                strDef.ReleaseBuffer();
                szDefaultDir[strDef.GetLength()] = 0;

这样也是一种方法吧。

时间: 2024-10-10 09:41:40

MFC记住上次路径---遇到的一些问题的相关文章

JFileChooser记住上次选择的路径

String saveFolder = "C:\\"; Preferences pref = Preferences.userRoot().node( this.getClass().getName()); String lastPath = pref.get("lastPath", ""); JFileChooser fc = null; if (!lastPath.equals("")) { fc = new JFileC

windows客户端开发--使你的客户端运行时记住上次关闭的大小和位置

几乎所有的windows客户端都可以调整大小,所以用户根据自己的喜好调整客户端的大小和位置. 但是当该客户端退出后,重新运行客户端的时候,我们往往又要调整自己喜好的大小和位置. 微信的windows客户端做了记住客户端退出时候的大小和位置,下次运行的时候直接,窗口直接显示为你喜好的大小和位置. 现在的任务就是八一八这个小小的功能. 首先,你肯定是想到了使用配置文件.再客户端退出的时候,把客户端窗口的信息记录在一个配置文件中,一般都是.ini文件.读写配置文件 很简单,这里就不再赘述了. 但是使用

Sublime Text 2中关闭记住上次打开的文件

每次编辑一个文件,Crtl+w好累,有木有?如果关闭Sublime Text记住上次打开的文件这个功能呢? 1.打开Sublime Text 2—[Preferences]—[settings—user]添加以下代码 "hot_exit": false, "remember_open_files": false 2.保存再重启试试? ps:如果出现粉色警告,请使用逗号分割代码: 我的配置: { "font_size": 12, "ign

C# 文件与路径操作

OpenFileDialog private void btnOpenFileDialog_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.InitialDirectory = @"C:\SeeSharp\LYH"; //设置起始路径 openFileDialog.Title = "打开文件"; //对话框

MFC框架剖析和消息机制

即便是基于MFC的应用程序,建立窗口类也是会遵循如下的过程: 设计窗口类->注册窗口类->生成窗口->显示窗口->更新窗口->消息循环->消息路由到窗口过程函数处理.下面就剖析一下在MFC中是如何完成上述过程的. (1)每个应用程序都有且仅有一个应用类的全局变量theApp,全局变量先于WinMain函数进行处理. (2)WinMain函数体在APPMODUL.CPP文件中,定义如下: extern "C" int WINAPI _tWinMain(

[oldboy-django][2深入django]Form组件功能: 数据格式验证 + 保留上次输入的值(如果有很多输入项,这样正确项不必重复输入,错误项也能提示错误信息)

1 需求:登录或者注册页面存在以下问题 - 无法记住上次提交的内容,(如果有很多输入项,这样正确项不必重复输入,错误项也能提示错误信息)- 重复进行提交数据的校验(数据是否为空,长度大小等等) 2 django的Form组件实现 2.1 Form组件实现数据验证方法 2.1.1 流程操作 - 定义规则(数据的格式,字段必须和表单上name属性一致) class LoginForm(Form): 字段名 = fields.xxFields(参数) # 定义了一个输入框的数据格式要求 实例化对象ob

MFC中的Debug Assertion Failed 如何查找原因

编写MFC程序时经常会遇到下图所示的断言失败问题 报错对话框中给出了一个目录,是在F盘,但是查找之后会发现电脑里可能根本没有这个目录. 最后发现可以在VS的安装目录下找到这个文件: \atlmfc\src\mfc 这部分路径是固定的. 找到文件,打开,看到报错提示的592行. ASSERT(pSocket!=NULL); 原来是指针为空导致ASSERT报错. 可以在自己程序里把指针处理的地方加个ASSERT或者try-catch一下. 参考文献: [转]dlgdata.cpp line 40 断

Node.js v0.12.0API手册--文件系统

File System Stability: 3 - Stable 文件系统模块是一个简单包装的标准 POSIX 文件 I/O 操作方法集.您可以通过调用require('fs')来获取该模块.文件系统模块中的所有方法均有异步和同步版本. 文件系统模块中的异步方法需要一个完成时的回调函数作为最后一个传入形参. 回调函数的构成由您调用的异步方法所决定,通常情况下回调函数的第一个形参为返回的错误信息. 如果异步操作执行正确并返回,该错误形参则为 null或者undefined. 如果您使用的是同步版

自己遇到的一些iOS面试题

1.OC内存管理机制 1).当你使用new,alloc和copy方法创建一个对象时,该对象的保留计数器值为 1.当你不再使用该对象时,你要负责向该对象发送一条release或autorelease消息.这样,该对象将在使用寿命结束时被销毁. 2).当你通过任何其他方法获得一个对象时,则假设该对象的保留计数器值为1,而且已经被设置为自动释放,你不需要执行任何操作来确保该对象被清理.如果你打算在一段时间内拥有该对象,则需要保留它并确保在操作完成时释放它. 3).如果你保留了某个对象,你需要(最终)释