在 Win7 上 GetOpenFileName 函数忽略 lpstrInitialDir 参数

发布于 2024-10-01 04:17:11 字数 687 浏览 2 评论 0原文

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

显然这是设计使然

lpstrInitialDir
LPCTSTR
初始目录。 不同平台选择初始目录的算法有所不同。

Windows 7:

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

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

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

I'm using GetOpenFileName and setting the lpstrInitialDir member of the OPENFILENAME struct to the directory I want as the initial directory. However on Win7 my app seems to remember what directory the user last opened and it ignores the lpstrInitialDir settings and goes to the last directory.

Apparently this is by design

lpstrInitialDir
LPCTSTR
The initial directory.
The algorithm for selecting the initial directory varies on different platforms.

Windows 7:

1.If lpstrInitialDir has the same value as was passed the first time the
application used an Open or Save As
dialog box, the path most recently
selected by the user is used as the
initial directory.
2.Otherwise, if lpstrFile contains a path, that path is the initial
directory.
3.Otherwise, if lpstrInitialDir is not NULL, it specifies the initial
directory.

Does anyone know how to stop this happening?

I want the directory I specify to be the initial directory regardless of what the file the user last opened i.e. I want condition 3 above to apply. I did the obvious and had a search through the registry but I couldn't find anything related to the problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

橘寄 2024-10-08 04:17:11

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

What happens if you set lpstrFile to the required initial directory path (i.e. lpstrInitialDir). If you are using lpstrFile to specify filename, then you may need to prepend initial directory path to the filename.

节枝 2024-10-08 04:17:11

我知道这个线程很旧,但我最近遇到了这个问题,并且找到了解决方案。
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 位进行了测试。

约翰内斯

I know this thread is old but I recently had this problem and I found a solution for it.
GetOpenFileName() saves the last used path in the registry. The path is:
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\

There are two keys, I am not sure which actually is used and under what circumstances but I delete my application's entry from both of them. The two keys are:
"LastVisitedPidlMRU" and "LastVisitedPidlMRULegacy".

The application names are saved as RegBinary values with a 16 bit character encoding (this is the reason why it would not show up in a registry search...).
I came up with the following function to delete the registry entries forcing Windows to believe that GetOpenFileName() has never before been called by my application:

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);
}

Just call this function before you call GetOpenFileName() and you're fine.

I tested with Windows 10, Version 19042.1052, 64bit.

Johannes

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文