定制PocketPC文件夹列表

PocketPC设备上,当启动Pocket Word或Pocket Excel等标准应用程序时,通常会显示一个文件列表,用户可以通过左上角的下拉菜单选择要查看的文件夹。这类似于桌面环境中的“文件打开”对话框。本文将展示如何自定义这个文件夹列表,例如,只显示名称中包含字母"L"的文件夹,并隐藏“所有文件夹”和“添加/删除文件夹”的选项。对于始终在SD卡上保存文档的应用程序,可以限制只显示SD卡文件夹。或者从列表中移除不必要的“模板”和“注释”文件夹。

DocList 控件在PocketPC中存在一些缺陷。首先,尽管它显示了每个存储卡上存在的文件夹以及"My Documents"下的文件夹,但它不允许用户从第一张存储卡以外的任何地方选择文件夹。这在像Mitac这样的系统上是个问题,它们将内置的备份闪存盘视为主要存储,而将SD卡视为次要存储。为了对用户友好,可以隐藏所有在次要存储卡上的文件夹。其次,如果在多个位置有同名的文件夹(例如"My Documents\Lu"和"Storage Card\Lu"),下拉文件夹列表会将它们合并在一起。但如果一个是用不同的大小写书写的,那么它们在选择时会合并,但在显示时不会合并。

预备知识

本文的代码使用了标准模板库(STL)。每个人都应该使用STL。下载STL,由Giuseppe Govi移植到eVC++。将其解压缩到项目的一个子目录中,命名为stl_eVC。接下来,在“项目 > 设置 > 编译器 > 预处理器”下,将目录stl_eVC添加到搜索路径列表中。

以下是需要包含的库。已经在STL中禁用了警告4018,因为它是虚假的。同时,在“项目 > 设置 > 链接器 > 输入”下,链接到doclist.lib和note_prj.lib。第一个是用于DocList控件,第二个是用于枚举文件夹。

#include <windows.h> #include <doclist.h> #include <projects.h> #pragma warning( push ) #pragma warning( disable: 4018 ) #include <string> #include <list> #pragma warning( pop ) using namespace std;

全局变量hdlc是DocList窗口。

构建一个假的文件夹列表

第一个问题是,尽管可以操作DocList的下拉文件夹列表,但无法检索项目名称。解决方案是构建认为DocList最终会包含的自己的“假”列表,并且以相同的顺序。这样就不必盲目地操作DocList了。

struct TProjectInfo { wstring fn; bool valid; int id; bool operator<(const TProjectInfo &b) const { return _wcsicmp(fn.c_str(), b.fn.c_str()) < 0; } }; list<TProjectInfo> dlcprojects;

全局变量dlcprojects维护假列表。注意DocList对文件夹排序是不区分大小写的;必须做同样的事情,因此使用了比较运算符。变量id稍后将在子类化DocList窗口时使用...

以下函数填充列表。(它还返回列表中有效条目的名称。)

wstring BuildProjectsList() { wstring validfn; dlcprojects.clear(); EnumProjectsEx(EnumCallback, 0, PRJ_ENUM_ALL_DEVICES, 0); dlcprojects.sort(); // The DocList's drop-down has some extra items: TProjectInfo pi; pi.valid = false; pi.fn = L"All Folders"; dlcprojects.push_front(pi); pi.fn = L"---"; dlcprojects.push_back(pi); pi.fn = L"Add/Delete..."; dlcprojects.push_back(pi); // Now we "unique" the list: if a folder exists in My Documents and also in a flash card, we only show it once. for (list<TProjectInfo>::iterator i = dlcprojects.begin(); i != dlcprojects.end(); i++) { list<TProjectInfo>::iterator j = i; j++; while (j != dlcprojects.end() && (*i).fn == (*j).fn) { if ((*j).valid && !(*i).valid) *i = *j; j = dlcprojects.erase(j); } if (validfn == L"" && (*i).valid) validfn = (*i).fn; } return validfn; }

注意函数EnumProjectsEx。在PocketPC术语中,“项目”是"My Documents"的任何直接(非嵌套)子文件夹,或者是任何存储卡的任何直接子文件夹。它使用以下回调:

BOOL CALLBACK EnumCallback(PAstruct *pa, LPARAM lp) { wchar_t *fn; if (pa->m_IDtype != FILE_ID_TYPE_OID) fn = pa->m_szPathname; else { CEOIDINFO cinf; CeOidGetInfo(pa->m_fileOID, &cinf); fn = cinf.infDirectory.szDirName; } TProjectInfo pi; // Get the "display-name" (ie. without the path) wchar_t *c = fn, *lastslash = c; while (*c != 0) { if (*c == '\\') lastslash = c + 1; c++; } pi.fn = lastslash; // and our arbitrary 'validity' criterion: pi.valid = (wcschr(lastslash, 'l') != 0); pi.valid |= (wcschr(lastslash, 'L') != 0); dlcprojects.push_back(pi); return TRUE; }

接下来,将子类化DocList控件。将拦截它的菜单事件,并根据需要更改菜单。使用了一个巧妙的策略来隐藏不想要的菜单项:即拦截WM_MEASUREITEM并将它们的高度设置为零!以下是子类过程:

WNDPROC OldDLCProc = 0; LRESULT CALLBACK NewDLCProc(HWND hs, UINT msg, WPARAM wParam, LPARAM lParam) { if (msg == WM_INITMENUPOPUP) { BuildProjectsList(); // just to be sure we're fresh // We will correlate menu-item IDs with 'dlcprojects' LRESULT ret = CallWindowProc(OldDLCProc, hs, msg, wParam, lParam); HMENU hm = (HMENU)wParam; wstring ws; list<TProjectInfo>::iterator it = dlcprojects.begin(); for (unsigned int pos = 0; ; pos++, it++) { MENUITEMINFO minf; ZeroMemory(&minf, sizeof(minf)); minf.cbSize = sizeof(minf); minf.fMask = MIIM_ID; BOOL res = GetMenuItemInfo(hm, pos, TRUE, &minf); if (!res) break; (*it).id = minf.wID; } return ret; } else if (msg == WM_MEASUREITEM) { MEASUREITEMSTRUCT *ms = (MEASUREITEMSTRUCT*)lParam; bool valid = false; for (list<TProjectInfo>::const_iterator i = dlcprojects.begin(); i != dlcprojects.end(); i++) { if ((*i).id == (int)ms->itemID) valid = (*i).valid; } LONG ret = CallWindowProc(OldDLCProc, hs, msg, wParam, lParam); if (!valid) { ms->itemWidth = 1; ms->itemHeight = 0; } return ret; } return CallWindowProc(OldDLCProc, hs, msg, wParam, lParam); } case WM_CREATE: { wstring initf = BuildProjectsList(); DOCLISTCREATE dlc; ZeroMemory(&dlc, sizeof(dlc)); dlc.dwStructSize = sizeof(dlc); dlc.hwndParent = hwnd; dlc.pszFolder = initf.c_str(); dlc.pstrFilter = L"All files\0*.*\0Text\0*.pwd;*.txt\0"; dlc.wId = 102; hdlc = DocList_Create(&dlc); OldDLCProc = (WNDPROC)SetWindowLong(hdlc, GWL_WNDPROC, (LONG)NewDLCProc); RECT rc; GetClientRect(hwnd, &rc); MoveWindow(hdlc, 0, 0, rc.right, rc.bottom, false); DocList_Refresh(hdlc); }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485