I have a wrapper application that needs to identify all the XP Mode applications published; these all reside within a single folder, and I'm using Qt to obtain all the .lnk files.
This bit works - the trouble is, all the Virtual PC applications use rundll32 in order to kick off a virtual machine and/or its app (e.g. %SystemRoot%\system32\rundll32.exe %SystemRoot%\system32\VMCPropertyHandler.dll,LaunchVMSal "Windows XP Mode" "||some_id" "some_name"
), and so I need to read the full target.
Reading the MSDN Docs, GetArguments()
on an IShellLink
should be returning this data - but it only ever retrieves the path to rundll32.exe
, and never with any trailing command line data. GetPath()
does the same, as expected, but I see no other methods to call that might be able to obtain the data I need.
I created a test shortcut with different argument styles (/param
, -param
and plain param
), but nothing makes a difference. It's not just Virtual PC links with the fault - this applies to all shortcuts.
Here's the function code:
QString GetShortcutTarget(const char* shortcut)
{
IShellLink* psl = NULL;
IPersistFile* ppf = NULL;
wchar_t wsz[MAX_PATH];
wchar_t target[MAX_PATH * 4]; // w/e
QString retval;
if ( MultiByteToWideChar(CP_ACP, 0, shortcut, -1, wsz, MAX_PATH) == 0 )
goto cleanup;
if ( FAILED(CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl)) )
goto cleanup;
if ( FAILED(psl->QueryInterface(IID_IPersistFile, (void **)&ppf)) )
goto cleanup;
if ( FAILED(ppf->Load(wsz, STGM_READ)) )
goto cleanup;
// GetPath() and GetArguments return the same
//if ( NOERROR != psl->GetPath(target, _countof(target), nullptr, 0) )
if ( NOERROR != psl->GetArguments(target, _countof(target)) )
goto cleanup;
retval = QString::fromWCharArray(target);
cleanup:
if ( ppf )
ppf->Release();
if ( psl )
psl->Release();
return retval;
}
EDIT
Not redefining an interface anywhere, including and linking with:
#include <objidl.h> // IPersistFile
#include <shlobj.h> // IShellLink
#pragma comment ( lib, "ole32.lib" )
#pragma comment ( lib, "uuid.lib" )
Only other COM related code is in a constructor and destructor elsewhere (yes, is already called!):
CoInitialize(NULL);
...
CoUninitialize();
Qt hopefully shouldn't have anything to do with it, as COM is definitely opening and reading the .lnk..
I discovered the problem - the input shortcut was the .lnk, but not the absolute file path; as my current directory wasn't set to where the shortcut was located, this was naturally making it fail to load.
I had Qt iterating over absolute paths, but I was only passing in the filename when searching for the target. I amended my previous call elsewhere from:
file_info.fileName()
to:
file_info.absoluteFilePath()
and this has fixed the issue!