Win32程序如何获取只有数字的目录

X.D.Washington 2021-04-16 08:47:50
平台:Windows
语言:C
IDE:Visual Studio 2019 Community

我正在做一个读写Windows配置文件(*.ini)的小程序。配置文件所在目录都是纯数字,非纯数字的目录下没有配置文件。程序中使用FindFirstFile和FindNextFile来枚举给定目录,然后获取给定目录下只含有数字字符的子目录名称,放到一个下拉列表框(组合框,ComboBox)里面。
以下是相关代码:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static HWND hComboBox;

switch (message)
{
case WM_CREATE:
hComboBox = CreateWindow(WC_COMBOBOX,
TEXT(""),
CBS_DROPDOWN | WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_SORT,
90, 23, 130, 400,
hwnd, NULL, NULL, NULL);

static TCHAR Folder[MAX_PATH];
WIN32_FIND_DATA ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError = 0;
HRESULT hr = SHGetFolderPathW(0, CSIDL_MYDOCUMENTS, 0, 0, Folder);
if (SUCCEEDED(hr))
{
StringCchCat(Folder, MAX_PATH, TEXT("\\work"));

if (DirectoryExists(Folder))
{
StringCchCat(Folder, MAX_PATH, TEXT("\\*"));
hFind = FindFirstFile(Folder, &ffd);
}
else
{
MessageBox(hwnd, TEXT("directory does not exist."), TEXT("error"), MB_ICONERROR);
}

if (INVALID_HANDLE_VALUE == hFind)
{
return 0;
}

do
{
if (ffd.cFileName[0] == '.') continue; // 跳过当前目录“.”、上一级目录“..”和隐藏目录

if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // 只要目录,不要文件
{
BOOL onlyDigit = TRUE;

for (int i = 0; i < sizeof(ffd.cFileName); i++)
{
if (ffd.cFileName[i] < '0' || ffd.cFileName[i] > '9')
{
onlyDigit = FALSE;
}
}

if (onlyDigit)
{
// 将只有数字的目录名称放到下拉列表框里面
SendMessage(hComboBox, (UINT)CB_ADDSTRING, (WPARAM)0, (LPARAM)ffd.cFileName);
}
}
}
while (FindNextFile(hFind, &ffd) != 0);

FindClose(hFind);
}
else
{
MessageBox(hwnd, TEXT("Failed to get special folder."), TEXT("ERROR"), MB_ICONERROR);
}
[其它代码片段]


在上述do...while循环里面,先是用
if (ffd.cFileName[0] == '.') continue;
来过滤掉当前目录“.”、上一级目录“.”和隐藏目录,然后用
if (ffd.cFileName[i] < '0' || ffd.cFileName[i] > '9')
遍历目录名称中的每个字符,如果含有非数字字符,就跳过该目录名称,处理下一个目录名称。

然而程序运行后,ComboBox里面啥也没有,是空的。

不知道是上面的代码哪里出了问题,或者有更好的方法来判断目录名称是否纯数字,还请大佬们指点一二。

之前是用C#和WinForm来做这个小程序的,现在改成C和Win32 GDI,突然感觉C#里面对Windows目录、文件、字符串的处理更轻松许多,但是Windows 10下的WinForm没法兼容Windows 7(需要安装对应的.NetFramework),而且C#里面也要调用GetPrivateProfileString这个Win API函数来读写ini文件,所以才改用C来写win32。

现在碰到字符串处理的问题,一时半会儿压根不懂该怎么弄。如果是纯C语言内的字符串处理字符串还好(像上面的代码应该就能正常运行了),可现在是在Windows环境下,救救孩子吧...

...全文
213 3 打赏 收藏 举报
写回复
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
X.D.Washington 2021-04-17
引用 1 楼 zara 的回复:
程序设计类的问题,不应发到相应语言的开发版块么? 我觉得,先在 Ln59 SendMessage() 上下断点,看看是否被触发,以确定问题到底在查找判断方面,还是列表控件方面;然后再次划分最终确定问题所在了。
感谢大佬指点! 版块做了调整。Ln59是正常的,应该是Ln50出了问题,但是具体如何还在试验当中...
  • 打赏
  • 举报
回复
X.D.Washington 2021-04-17
引用 1 楼 zara 的回复:
程序设计类的问题,不应发到相应语言的开发版块么? 我觉得,先在 Ln59 SendMessage() 上下断点,看看是否被触发,以确定问题到底在查找判断方面,还是列表控件方面;然后再次划分最终确定问题所在了。
大佬我又回来了 问题已经得到解决!我按您给的思路去试了一下,确定不是列表控件的问题,而是查找判断方面出了问题。具体如下: 对于纯数字的目录名称,程序也没有将其放到 ComboBox 里面。上面代码中 Ln48 里面 ffd.cFileName 的 Windows 内部定义如下:
    _Field_z_ WCHAR  cFileName[ MAX_PATH ];
其中 MAX_PATH = 260,也就是说 ffd.cFileName 是一个长度为 260 个字符的宽字符数组,每一个宽字符都是 2 字节的 Unicode 字符,所以 sizeof(ffd.cFileName) 的值是 520。 sizeof 返回的总是括号中的总字节数,所以 Ln49 其实已经发生了数组下标越界。当时编译器报下标越界的时候我还纠结半天,不明白为什么会越界,原来是因为在做 < '\0' 和 > '\9' 这样的判断的时候总是容易按 ASCII 的方式去思考,就以为 sizeof(ffd.cFileName) 的值等于 260。虽然 VS 里面程序正常运行。 问题就发生在这个 for 循环里面。ffd.cFileName 是一个 Null-terminated string,当碰到“10086”这样的目录名称时,ffd.cFileName 的具体值如下:
ffd.cFileName[0] = '1';
ffd.cFileName[1] = '0';
ffd.cFileName[2] = '0';
ffd.cFileName[3] = '8';
ffd.cFileName[4] = '6';
ffd.cFileName[5] = '\0';
ffd.cFileName[6] = [initialize value];
...
...
...
ffd.cFileName[258] = [initialize value];
ffd.cFileName[259] = [initialize value];
当 for 循环中的 i = 5 时,Ln52 中的 onlyDigit = FALSE 就被执行了。接着,i 继续增大,for 循环继续执行,onlyDigit 的值会一直是FALSE,直到循环结束。所以这就是为什么对于纯数字的目录名称,程序也没有将其放到ComboBox里面。 当然,对于非纯数字的目录名称,上述for循环是没有问题的。 找到原因后,我重新写了代码,在 ffd.cFileName 中 加入了对 NULL 字符的处理,程序终于正常运行了:
			[其它代码片段]
			do
			{
				if (ffd.cFileName[0] == '.') continue;

				if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
				{
					BOOL IsNumericString = TRUE;

					for (int i = 0; i < 260; i++)
					{
						if (ffd.cFileName[i] == '\0')
						{
							break;
						}
						else
						{
							if ((ffd.cFileName[i] < '0') || (ffd.cFileName[i] > '9'))
							{
								IsNumericString = FALSE;
								break;
							}
						}
					}

					if (IsNumericString == TRUE)
					{
						SendMessage(hComboBox, (UINT)CB_ADDSTRING, (WPARAM)0, (LPARAM)ffd.cFileName);
					}
				}

			}
			while (FindNextFile(hFind, &ffd) != 0);
			[其它代码片段]
在这里再次感谢大佬! 2021-4-17 17:30:10
  • 打赏
  • 举报
回复
zara 2021-04-16
程序设计类的问题,不应发到相应语言的开发版块么?
我觉得,先在 Ln59 SendMessage() 上下断点,看看是否被触发,以确定问题到底在查找判断方面,还是列表控件方面;然后再次划分最终确定问题所在了。
  • 打赏
  • 举报
回复
相关推荐
发帖
Windows SDK/API

1216

社区成员

C++ Builder Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
帖子事件
创建了帖子
2021-04-16 08:47
社区公告
暂无公告