【问题标题】:On Win7 GetOpenFileName function ignores the lpstrInitialDir arguament在 Win7 上 GetOpenFileName 函数忽略 lpstrInitialDir 参数
【发布时间】:2010-11-07 09:48:11
【问题描述】:

我正在使用GetOpenFileName 并将OPENFILENAME 结构的lpstrInitialDir 成员设置为我想要作为初始目录的目录。但是在 Win7 上,我的应用程序似乎记住了用户上次打开的目录,它忽略了 lpstrInitialDir 设置并转到最后一个目录。

Apparently this is by design

lpstrInitialDir
LPCTSTR
初始目录。 选择初始目录的算法因平台而异。

Windows 7:

1.如果 lpstrInitialDir 与第一次传递的值相同 应用程序使用了打开或另存为 对话框,最近的路径 由用户选择被用作 初始目录。
2.否则,如果 lpstrFile 包含路径,则该路径是初始 目录。
3.否则,如果lpstrInitialDir不为NULL,则指定初始 目录。

有谁知道如何阻止这种情况发生?

我希望我指定的目录是初始目录,而不管用户上次打开的文件是什么,即我希望应用上面的条件 3。我做了显而易见的事情并通过注册表进行了搜索,但我找不到与问题相关的任何内容。

【问题讨论】:

    标签: windows-7


    【解决方案1】:

    我知道这个帖子很旧,但我最近遇到了这个问题,我找到了解决方案。 GetOpenFileName() 将上次使用的路径保存在注册表中。路径是: HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\

    有两个键,我不确定实际使用的是哪个以及在什么情况下,但我从它们中删除了我的应用程序条目。两个关键是: "LastVisitedPidlMRU" 和 "LastVisitedPidlMRULegacy"。

    应用程序名称保存为 16 位字符编码的 RegBinary 值(这就是它不会出现在注册表搜索中的原因...)。 我想出了以下函数来删除注册表项,迫使 Windows 相信 GetOpenFileName() 以前从未被我的应用程序调用过:

    void clear_path_in_registry ()
    {
      char keypath[PATH_MAX];
      char *keys[] = { "LastVisitedPidlMRU", "LastVisitedPidlMRULegacy" };
    #define NO_OF_KEYS (sizeof(keys)/sizeof(*keys))
      int keynr;
      HKEY hkey;
      int res;
      char val_data[BUFLEN];
      DWORD val_len, data_len;
      int i;
      char val_name[VALUELEN];
      char progname[PATH_MAX];
      char *p, *q;
      char exename[PATH_MAX];
      int index;
      int *pi , *pj;
    
      do_debug (1, "clear_path_in_registry()\n");
    
      GetModuleFileName (NULL, progname, sizeof(progname));
      p = strrchr (progname, '\\');
      if (p)
        p ++;
      strncpy (exename, p, sizeof(exename)-1);
      keynr = 0;
      do
      {
        snprintf (keypath, sizeof(keypath),
         "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\%s",
         keys[keynr]);
    
        res = RegOpenKeyEx (HKEY_CURRENT_USER,keypath,0,KEY_ALL_ACCESS,&hkey);
        if (res == ERROR_SUCCESS)
        {
          i = 0;
          val_len = sizeof (val_name);
          data_len = sizeof (val_data);
          while (RegEnumValue(
                  hkey,i,val_name,&val_len,NULL,NULL,(BYTE *)val_data,&data_len)
            == ERROR_SUCCESS)
          {
            if (stricmp(val_name, "MRUListEx"))
            {
              /* is not the "MRUListEx" value -> extract program name
               *
               * for some (unknown) reason the program names are not stored as
               * RegSZ but rather as RegBinary values. They are encoded in some
               * dual-byte encoding. In my experiments the high bytes are
               * always 0x00; so the transcoding is simple, just skip the high
               * bytes. Probably there is a WIN32 API call for this but I did
               * dig into that for now ...
               */
              p = progname;
              q = val_data;
              while (*q)
              {
                *p++ = *q++;
                q ++;
              }
              *p = '\0';
              /* the index in the MRUList is the value name */
              index = atoi (val_name);
              if (stricmp (progname, exename) == 0)
              {
                /* found the value with current executable name -> delete it */
                res = RegDeleteValue (hkey, val_name);
                if (res == ERROR_SUCCESS)
                {
                  /* delete the entry from the MRUList
                   *
                   * The MRUListEx value is a of the type RegBinary as well.
                   * The data structure is fairly simple: just 4-byte integers
                   * one after the other; -1 marks the end of the list
                   */
                  data_len = sizeof (val_data);
                  res = RegQueryValueEx (hkey, "MRUListEx", NULL, NULL,
                                                   (BYTE*)val_data, &data_len);
                  if (res == ERROR_SUCCESS)
                  {
                    pi = (int *)val_data;
                    pj = (int *)val_data;
                    while (*pj != -1)
                    {
                      if (*pj == index)
                      {
                        pj ++;
                        data_len -= sizeof(int);
                      }
                      *pi++ = *pj++;
                    }
                    *pi = *pj;
                    res = RegSetValueEx (hkey, "MRUListEx", 0, REG_BINARY,
                                                  (BYTE *)val_data, data_len);
                    if (res != ERROR_SUCCESS)
                    {
                      do_debug (1,"ERROR writing registry value 'MRUListEx'\n");
                    }
                  } else
                  {
                    do_debug (1, "ERROR reading registry value 'MRUListEx'\n");
                  }
                } else
                {
                  do_debug (1,"ERROR deleting registry value '%s'\n",val_name);
                }
              }
            }
            val_len = sizeof (val_name);
            data_len = sizeof (val_data);
            i ++;
          } /* iterate through registry values */
        }
        res = RegCloseKey (hkey);
        if (res != ERROR_SUCCESS)
        {
          do_debug (1, "Error closing registry key '%s'\n", keys[keynr]);
        }
        keynr ++;
      } while (keynr < NO_OF_KEYS);
    }
    

    在调用 GetOpenFileName() 之前调用这个函数就可以了。

    我使用 Windows 10,版本 19042.1052,64 位进行了测试。

    约翰内斯

    【讨论】:

      【解决方案2】:

      如果将lpstrFile 设置为所需的初始目录路径(即lpstrInitialDir)会发生什么情况。如果您使用lpstrFile 指定文件名,那么您可能需要在文件名前面加上初始目录路径。

      【讨论】:

      • 谢谢,这是我需要的建议。如果我将 lpstrFile 设置为完整路径,则 OpenFile 对话框会在 lpstrFile 中指定的目录中打开,并且它可以使用通配符,如 C:\path\*.xml。
      • 这对我不起作用,我得到“'error 12290.'打不开。
      猜你喜欢
      • 2010-11-04
      • 2021-02-18
      • 2016-04-24
      • 1970-01-01
      • 2017-07-04
      • 1970-01-01
      • 2015-08-24
      • 2017-03-08
      • 2020-03-15
      相关资源
      最近更新 更多