【问题标题】:IPersistFile::Save method keeps failing to save the shortcutIPersistFile::Save 方法一直无法保存快捷方式
【发布时间】:2013-09-01 01:40:01
【问题描述】:

我正在尝试将我的应用程序的快捷方式保存在启动文件夹中。这一切都可以编译,但它无法真正保存游戏。该错误似乎发生在hres = ppf->Save(wsz, TRUE);,其中hrs 设置为-2147024891。如果这意味着特定的东西,我还没有发现什么。我的代码几乎是从 MSDN 逐字复制的,所以我很困惑为什么它不起作用。也许我没有权限将快捷方式保存到启动文件夹?再说一次,我对这一切也很陌生,所以这可能是我犯的一些基本错误。我也在复制我所有的#includes,以防万一出现问题。

编辑:
首先,为避免混淆,这是基于 CLI 的 C++。

检查 hres 是否有错误只是 MDSN 代码的一部分。这实际上与网站示例中的代码几乎完全相同。我已经设置了断点,这就是我知道在运行hres = ppf->Save(wsz, TRUE); 之后hrs 变为-2147024891 的方式。

如果这些错误,mediaMaestroLocation 设置为"C:\Users\Keith\Documents\Visual Studio 2012\Projects\MediaMaestro\Debug\MediaMaestro.exe",startupDestination 设置为"C:\Users\Keith\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"。虽然 exe 位置看起来不错,但我想知道在目标文件夹路径之后没有 \ 是否重要。我已经检查过了,但我需要先花几分钟弄清楚如何做。

#include <windows.h>
#include <string>
#include <stdio.h>
#include <shobjidl.h>
#include <shlobj.h>
#include "objbase.h"
#include <objidl.h>
#include <shlguid.h>
#include <winnls.h>

#using <System.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Windows::Forms;

char startupDestination[MAX_PATH];
char mediaMaestroLocation[MAX_PATH];

DWORD nChars = 0;
BOOL yChars = 0;

HRESULT CreateLink() 
{ 
    CoInitializeEx( NULL, 0 );
    HRESULT hres = 0;
    IShellLink* psl; 

    if (SUCCEEDED(hres)) 
    { 

        // Get a pointer to the IShellLink interface. It is assumed that CoInitialize
        // has already been called.
        hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl); 
        if (SUCCEEDED(hres)) 
        { 
            IPersistFile* ppf; 

            // Set the path to the shortcut target and add the description. 
            psl->SetPath(mediaMaestroLocation); 
            psl->SetDescription("Media Maestro"); 

            // Query IShellLink for the IPersistFile interface, used for saving the 
            // shortcut in persistent storage. 
            hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); 

            if (SUCCEEDED(hres)) 
            { 
                WCHAR wsz[MAX_PATH]; 

                // Ensure that the string is Unicode. 
                MultiByteToWideChar(CP_ACP, 0, startupDestination, -1, wsz, MAX_PATH); 


                // Add code here to check return value from MultiByteWideChar 
                // for success.

                // Save the link by calling IPersistFile::Save. 
                hres = ppf->Save(wsz, TRUE); 
                ppf->Release(); 
            }
            psl->Release(); 
        }
    }
    CoUninitialize();
    return hres; 
}


这是调用该函数的 UI 中的单击事件:

void settingsLaunchOnStart_Click( Object^ Sender, EventArgs^ e )
   {

       if (settingsLaunchOnStart->Checked == false)
       {
            HRESULT r;
            nChars = GetModuleFileName( NULL, mediaMaestroLocation, sizeof(mediaMaestroLocation) );
            yChars = SHGetFolderPath( NULL, CSIDL_STARTUP, NULL, SHGFP_TYPE_CURRENT, startupDestination);
            r = CreateLink();
       }
       else if (settingsLaunchOnStart->Checked == true)
       {

        //code to remove the shortcut
       }
   }



有什么我遗漏的吗?

【问题讨论】:

  • 对不起,hres 是什么,你在什么地方声明过吗?
  • hres is an HRESULT。 if() 检查有点毫无意义,因为它刚刚初始化为 0,在我见过的每次运行 Windows 时,它都是 S_OK 的同义词,随后总是评估为真。不是您的问题,但确实回答了@computer 的问题。您可能还想更新问题以表明这使用 CLI;不仅仅是 C++。
  • 也就是说,我将从 all COM 调用开始检查有效的返回码。我对基于 CLI 的 C++ 不是很熟悉,但是您传递给 SetPath 和 SetDescription 的字符串文字对我来说似乎很奇怪,因为它们很窄。这是使用 Unicode 设置编译的吗? -2147024891 的值是 0x80070005 的同义词,可怕的 E_FAIL,所以肯定有什么不对劲。
  • 哇。我可以发誓它被设置为使用 Unicode 设置进行编译,但它被设置为多字节。这是我问题的根源吗?我将其换成 unicode 并将路径变量更改为 wchar_t 类型,但它仍然无法正常工作。我肯定会觉得这是失败的,因为我输入了错误的路径。
  • 我想通了。当我有工作代码要发布时,我会回答我自己的问题,但事实证明我需要将"filename.lnk" 附加到startupLocation 文件路径上。

标签: c++ shortcut


【解决方案1】:

事实证明,仅命名输出文件夹路径是不够的,我还必须命名文件和扩展名。考虑到我认为我没有见过其他例子这样做,这对我来说似乎很奇怪。无论如何,这是我更新的工作代码:

HRESULT CreateLink() 
{ 
    CoInitializeEx( NULL, 0 );
    HRESULT hres = 0;
    IShellLink* psl; 

    if (SUCCEEDED(hres)) 
    { 

        // Get a pointer to the IShellLink interface. It is assumed that CoInitialize
        // has already been called.
        hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLink, (LPVOID*)&psl); //CLSCTX_ALL CLSCTX_INPROC_SERVER (void**)&psl (LPVOID*)&psl
        if (SUCCEEDED(hres)) 
        { 
            IPersistFile* ppf; 

            // Set the path to the shortcut target and add the description. 
            psl->SetPath(mediaMaestroLocation);
            psl->SetDescription(L"Media Maestro"); 
            psl->SetIconLocation(mediaMaestroLocation, 0);

            // Query IShellLink for the IPersistFile interface, used for saving the 
            // shortcut in persistent storage. 
            hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); //(void**)&psl (LPVOID*)&ppf

            if (SUCCEEDED(hres)) 
            { 
                WCHAR wsz[MAX_PATH]; 

                // Save the link by calling IPersistFile::Save. 

                hres = _wmakepath_s( wsz, _MAX_PATH, NULL, startupDestination,
                      L"MediaMaestro", L"lnk" );

                hres = ppf->Save(wsz, TRUE); 
                ppf->Release(); 
            }
            psl->Release(); 
        }
    }
    CoUninitialize();
    return hres; 
}



添加 _wmakepath_s 让我可以将程序名称及其扩展名附加到从 SHGetFolderPath 获得的文件路径上。一旦我将它输入 IPersistFile 接口,它就会按原样保存。

【讨论】:

    【解决方案2】:

    您只将 hres 初始化为 0,然后您检查它是否成功?你从来没有真正在某处声明它,-2147024891 可能意味着该变量尚未初始化。

    一个疯狂的猜测是,它甚至从未达到:hres = ppf-&gt;Save(wsz, TRUE); 行,因此它没有被初始化:P 尝试在调试时放置一些断点,并且可能使用一些手表来查看变量 :)

    最好的问候。

    【讨论】:

    • 这是不正确的。 hres 初始化为 0 与 S_OK 同义,它将评估 SUCCEEDED(hres) 为真。我同意初始检查毫无意义,但初始化 hres 不是问题(因为它实际上已初始化)。
    • 我已经添加了一些断点,并且已经在变量处达到了峰值。我可能应该从一开始就包含这些信息,但我编辑了我的问题来回答你的一些问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-06
    相关资源
    最近更新 更多