Resolving shortcut paths in Code Blocks?

Apr 23, 2015 at 10:45pm
I'm creating a file browsing program using SFML, and have made a good amount of progress. However, so far it is unable to work properly with shortcuts, and examples I've seen of how to do this have always come straight from MSDN for Visual C++, and Code::Blocks doesn't play nice with some of the libraries involved. Is there a practical way to retrieve the path from a lnk file in Code Blocks, or to determine if the shortcut goes to a file or folder?
Last edited on Apr 23, 2015 at 10:52pm
Apr 23, 2015 at 11:22pm
Seems this is what you are referring to? http://www.cplusplus.com/forum/windows/64088/
Apr 23, 2015 at 11:44pm
Yes, but that code won't compile in Code::Blocks. I've tried modifying it, importing libraries, etc. to no avail.
Apr 24, 2015 at 1:32pm
I just compiled this (had to make a few changes) with Code::Blocks using MinGW:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#define WIN32_LEAN_AND_MEAN
#define WINVER       0x0602
#define _WIN32_WINNT 0x0602
#define _WIN32_IE    0x0602

#include <windows.h>
#include <objbase.h>
#include <shlobj.h>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <iomanip>

#ifdef _UNICODE
#define TCOUT std::wcout
#define TCERR std::wcerr
#else
#define TCOUT std::cout
#define TCERR std::cerr
#endif

HRESULT ResolveIt(HWND hwnd, LPCTSTR lpszLinkFile, LPTSTR lpszPath, int iPathBufferSize);

int main()
{
	const TCHAR cachLinkFile[] = TEXT("D:\\dev\\projects.lnk");

	HRESULT hres = CoInitialize(NULL);

	if(SUCCEEDED(hres))
	{
		TCHAR achPath[MAX_PATH] = {0};
		hres = ResolveIt(NULL, cachLinkFile, achPath, MAX_PATH);
		if (SUCCEEDED(hres))
		{
			TCOUT << TEXT("Succeeded: path = ") << achPath << std::endl;
		}
		else
		{
			TCERR << TEXT("Failed: error = 0x") << std::hex << hres << std::dec << std::endl;
		}

		CoUninitialize();
	}

	return 0;
}

HRESULT ResolveIt(HWND hwnd, LPCTSTR lpszLinkFile, LPTSTR lpszPath, int iPathBufferSize)
{
	if (lpszPath == NULL)
		return E_INVALIDARG;

	*lpszPath = 0;

	// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
	// has already been called.
	IShellLink* psl = NULL;
	HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
	if (SUCCEEDED(hres))
	{
		// Get a pointer to the IPersistFile interface.
		IPersistFile* ppf = NULL;
		hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
		if (SUCCEEDED(hres))
		{
			// Add code here to check return value from MultiByteWideChar
			// for success.

			// Load the shortcut.
#ifdef _UNICODE
			hres = ppf->Load(lpszLinkFile, STGM_READ);
#else
			WCHAR wsz[MAX_PATH] = {0};
			// Ensure that the string is Unicode.
			MultiByteToWideChar(CP_ACP, 0, lpszLinkFile, -1, wsz, MAX_PATH);
			hres = ppf->Load(wsz, STGM_READ);
#endif

			if (SUCCEEDED(hres))
			{
				// Resolve the link.
				hres = psl->Resolve(hwnd, 0);

				if (SUCCEEDED(hres))
				{
					// Get the path to the link target.
					TCHAR szGotPath[MAX_PATH] = {0};
					hres = psl->GetPath(szGotPath, MAX_PATH, NULL, SLGP_SHORTPATH);

					if (SUCCEEDED(hres))
					{
						memcpy(lpszPath,szGotPath,iPathBufferSize);
					}
				}
			}

			// Release the pointer to the IPersistFile interface.
			ppf->Release();
		}

		// Release the pointer to the IShellLink interface.
		psl->Release();
	}
	return hres;
}


link with libole32.a and libuuid.a
Apr 24, 2015 at 5:12pm
It works! Thank you!

One quick question I had; does the first command on line 26 take a constant char? I know it doesn't work as a string. I need to figure out how to make the path of the link being resolved variable. Attempting to use constant chars or strings hasn't worked for me so far. For example, I made this slight change to test it out.

1
2
std::string X = "C:\\Desktop.lnk";
	const TCHAR cachLinkFile[] = TEXT(X);

error: initializer fails to determine size of cachLinkFile

When the "C:\\Desktop.lnk" is where the X is, it works great though.
I tried a couple other modifications in an attempt to apply X to the cachLinkFile, but no luck so far.

If I can get past this hurdle I should be able to integrate it into my file browser project, where it will be able to resolve link paths and browse the appropriate directory. Within the project, the browsing occurs by reading a vector of strings containing the directory listings, so the links to be resolved would be retrieved from there.

I think I have it figured out if I can determine the string length beforehand using
memcpy(cachLinkFile,X.c_str(),stringsize);
and initialize the cachLinkFile with a suitably large size of characters, though, as long as it occurs directly after cachLinkFile's initialization. For instance, this works:
1
2
3
    std::string X="C:\\Desktop.lnk";
	char cachLinkFile[64] = "";
    memcpy(cachLinkFile,X.c_str(),X.size());

I think I can take it from here. Thanks for the help!!
Last edited on Apr 24, 2015 at 7:00pm
Apr 24, 2015 at 6:53pm
I'm pretty sure you can just do this:
1
2
std::string X = "C:\Desktop.lnk";
const TCHAR *cachLinkFile = X.c_str();
Apr 24, 2015 at 7:03pm
That also works. Thanks a lot, Texan40!
Topic archived. No new replies allowed.