【问题标题】:GetSaveFileName() how to update the file extension in the "File name:" control?GetSaveFileName() 如何更新“文件名:”控件中的文件扩展名?
【发布时间】:2013-01-21 23:51:18
【问题描述】:

我有以下代码(提取)来显示另存为对话框:

char FileName[MAX_PATH] = "TestImage.jpg"

...

lpofn.lStructSize = sizeof(OPENFILENAME);
lpofn.hwndOwner = hWnd;
lpofn.hInstance = GetWindowInstance (hWnd);
lpofn.lpstrFilter = "JPG - JPEG File\0*.JPG\0TIF - TIFF File\0*.TIF\0PNG File\0*.PNG\0BMP - Bitmat File\0*.BMP\0";
lpofn.lpstrCustomFilter = NULL;
lpofn.nMaxCustFilter = NULL;
lpofn.nFilterIndex = 0;
lpofn.lpstrFile = FileName;
lpofn.nMaxFile = MAX_PATH;
lpofn.lpstrFileTitle = NULL;
lpofn.nMaxFileTitle = NULL;
lpofn.lpstrInitialDir = NULL;
lpofn.lpstrTitle = NULL;
lpofn.Flags = OFN_HIDEREADONLY | OFN_ENABLEHOOK | OFN_EXPLORER;
lpofn.nFileOffset = 0;
lpofn.nFileExtension = 0;
lpofn.lpstrDefExt = NULL;
lpofn.lCustData = NULL;
lpofn.lpfnHook = &UpdateFilename;
lpofn.lpTemplateName = NULL;
if(!GetSaveFileName(&lpofn)) return;

...

例如。 - 用户保存为,默认文件名 = "TestImage.jpg",默认文件类型 = JPG - 用户将文件类型更改为PNG,文件名控制保持在“TestImage.jpg”而不是更改为“TestImage.png”

我做错了吗?是否可以指示 GetSaveFileName() 更改扩展名,或者我是否必须有一个自定义另存为对话框(任何示例?)

我正在使用 Win32 API,VC6。

更新:这里是Hook函数:

UINT CALLBACK UpdateFilename(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uiMsg)
    {
         case WM_NOTIFY:
          // Check for CDN_TYPECHANGE etc
              return FALSE;
    }

    return FALSE;
}

请注意,钩子函数确实会在断点处停止。我故意不继续处理 CDN_TYPECHANGE,直到我弄清楚为什么启用钩子后对话框的外观会发生变化以及如何修复它。

【问题讨论】:

    标签: c winapi visual-c++-6


    【解决方案1】:

    为建议的文件名使用缓冲区,而不是静态字符串。

    char szFile[MAX_PATH]; 
    szFile[0] = '\0';
    lpofn.lpstrFile= szFile; 
    lpofn.nMaxFile = sizeof(szFile)/ sizeof(*szFile);
    

    除此之外,这是 Windows 的默认行为,可以追溯到 Win95 天。当您使用 VS6.0 时,您仍然拥有这些 DLL。我当时所做的是使用:

    lpofn.lpstrDefExt = (LPSTR)NULL
    

    这可以防止添加任何扩展。然后我在返回时检查了 lpofn.nFileExtension 以找出选择了哪个扩展名。

    if (lpofn.nFileExtension == 0)
    {
    // add default extension, no extension was selected/entered by user
    }
    else
    {
     // there is an extension, save as entered.
    }
    

    【讨论】:

    • 谢谢,这与我目前正在做的类似。我不知道这是默认行为。
    【解决方案2】:

    为了在对话框仍在运行时更新对话框,您需要在OPENFILENAME 结构中提供指向lpfnHook 回调的指针,并让回调处理CDN_TYPECHANGE 通知。它可以向对话框发送CDM_GETFILEPATHCDM_GETSPEC 消息以获取当前文件名,根据需要对其进行调整,然后发送CDM_SETCONTROLTEXT 消息以更新编辑字段(文件名编辑字段的ID 为0x442 ) 使用新值。

    更新:你的钩子代码没有问题。从 Windows Vista 开始,GetSaveFileName() 已被弃用,由Common Item Dialog 取代(并成为包装器)。 GSFN 对话框 UI 不会被 XP 中的挂钩更改,因此您必须使用 Vista+,在这种情况下启用挂钩只会导致包装器在内部调用 CID 时使用不同的设置。许多新的 CID 功能基于IShellItem,而不是文件名字符串,因此包装器删除了任何不能表示为旧样式文件名的内容,并使对话框看起来像 XP 和更早版本中的旧样式 GSFN 对话框.因此,您看到的是 Vista+ 下 GetSaveFileName()正常行为!如果您不喜欢它,请不要再使用GetSaveFileName()。请改用新的IFileSaveDialog 接口。事实上,如果您配置多种文件类型,将其中一种指定为默认扩展名,然后设置与默认扩展名匹配的初始文件名,它会为您原生更改文件扩展名。但如果您愿意,您也可以在代码中实现IFileDialogEvents 接口以接收OnTypeChange 通知,然后使用IFileDialog::SetFileName() 方法将显示的文件名更新为需要。

    【讨论】:

    • 谢谢,我实现了一个钩子,但对话框的外观完全改变了?不太清楚如何解释,但它从标准的另存为对话框更改为精简版。我尝试了 OFNHookProcOldStyle 和 OFNHookProc,两者看起来都不同,但给出了类似的精简对话框。是否可以实现一个钩子并保持标准外观?
    • 你能用你正在使用的实际钩子代码更新你的问题吗?
    • 完成,请注意,在对话框的外观得到解决之前,我故意不继续处理 CDN_TYPECHANGE。还要感谢您让我知道 CDN_TYPECHANGE,这是一个很好的指针。另外,因为我实际上并没有处理该消息,所以我返回了 FALSE 而不是 TRUE。
    猜你喜欢
    • 1970-01-01
    • 2011-05-14
    • 1970-01-01
    • 2013-05-20
    • 2019-09-23
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 2012-10-31
    相关资源
    最近更新 更多