A String Stuck Inside A Char Or TCHAR Array?

Mar 12, 2012 at 6:55am
So there's one function resolving links to their targets that I am still working with. Unfortunately in this weird instance it is required (And in other instances) that you create a memory buffer for storing a string for instance say we use the following windows C function like so

1
2
3
TCHAR UserPath[MAX_PATH];
ExpandEnvironmentStrings(L"%USERPROFILE%",UserPath, MAX_PATH);


That all works great and places your user path like in my case C:\Users\austin\Desktop inside of your UserPath memory buffer but there's just one problem:

You have this helpful string that's just C:\Users\austin\Desktop suck inside this 260 length buffer and YOU JUST WANT THE DARN STRING lol. You also can't just use this in another function. Like say (for the sake of argument) you wanted to rename a file on your desktop which would be using our function above

Well for the first part where the file is rename(
and that string would be UserPath - All of the unnecessary characters until you just have C:\Users\austin\Desktop.

Now technically in my case I could just create a buffer since I know how long it is but if you are using software on another computer you DON'T know how long those strings will be. This is a problem I have with functions like this one. What can be done about it?

Thanks guys
Last edited on Mar 12, 2012 at 6:55am
Mar 12, 2012 at 9:07am
Call the function first with NULL as second argument to get the required buffer size, allocate the memory and then call the function again. This way most win32 API works (not all though).

And please don't mix TCHARs with UNICODE strings, it is very bad behavior, stick with one of them.
Mar 12, 2012 at 8:04pm
Sorry modoran this just kills. What did I do wrong here with Unicode this is all TCHAR correct in the above code? What's the problem with the function itself above besides not knowing that you can set the second argument to null and get the buffer size needed?

Ok so using this this works and when you pass the char into a normal string then the length of that string is correct with the userpath exmaple
1
2
3
4
5
6
7
8
DWORD usize = ExpandEnvironmentStringsA("%USERPROFILE%",NULL,NULL);
char upath[MAX_PATH];
	ExpandEnvironmentStringsA("%USERPROFILE%",upath,(int)usize);

	string a;
	a = upath;

	cout << a << endl;

This is frustrating though because since you have the size of 17 in my case of usize why can't you JUST create an array with a length of 17?
You can't just create an array though like
char urpath[usize]
and if you use
char urpath[sizeof(usize)]
that's smaller than 17 i.e. 4 in this case.

So in short how can you JUST allocate enough memory to the DWORD of the string length that is returned by that function? Second this Unicode business etc. So you're saying USERPROFILE is Unicode in and of itself and therefore I should have used ExpandEnvironmentStringsA ????

Sorry man this is just ahhh! confusing. I really appreciate your help though I feel I'm learning a lot here.
Last edited on Mar 12, 2012 at 8:04pm
Mar 13, 2012 at 12:53am
I got it I think

1
2
3
4
5
6
7
8
9
10
//get buffer size needed
	DWORD usize = ExpandEnvironmentStringsA("%USERPROFILE%",NULL,NULL);
	
	char* userpath = new char[(int)usize];
    ExpandEnvironmentStringsA("%USERPROFILE%",userpath,(int)usize);
string a;
a = userpath;

delete userpath;


you have to use a dynamic size in this case which is a lot smarter then just throwing the string for the user path inside of a MAX_PATH size array correct? Is there anything wrong then modoran and others with the code above wouldn't that work fine at this point? Again you meant unicode because using Tchar's would be bad since USERPATH is a ANSI string right?
Mar 13, 2012 at 1:04am
you have to use a dynamic size
That's right.

Again you meant unicode because using Tchar's would be bad
Not quite. You were mixing TCHAR and Unicode by declaring the buffer to be TCHAR, but the environment variable as a Unicode constant. It should sort of be like this:
1
2
3
4
5
DWORD usize = ExpandEnvironmentStrings(TEXT("%USERPROFILE%"), NULL, 0);
TCHAR* userpath = new TCHAR[usize];
ExpandEnvironmentStrings(TEXT("%USERPROFILE%"), userpath, usize);
//...
delete [] userpath;
Mar 13, 2012 at 2:40am
kbw thanks but if you just used ExpandEnvironmentStringsA with the A at the end i.e. ANSI stuff then the example I used above would be acceptable though right?
Last edited on Mar 13, 2012 at 2:45am
Mar 13, 2012 at 3:53am
Yes, your Ansi version is correct.

Note: get rid of that cast of DWORD to int, is not needed.
Mar 13, 2012 at 6:23am
Okay so going by that logic using that trick won't appear to work in my program below since Loading links etc. doesn't have a return of DWORD size but HRESULT so essentially at the end of it all you get a string of charecters in a MAX_PATH array which is the path to a shortcut but it again couldn't be used in any other part of your program since it's stuck within max path I guess this is my real problem with this all along it just took me awhile to understand how to ask.

If anyone could think of a way around this to just got the path to an lnk file not inside a large memory buffer that would be amazing. LINKHOLD it's stuck in there.

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
107
108
#include <iostream>
#include <string>
#include <new>
#include <Windows.h>
#include <sstream>
#include <fstream>
#include <ObjBase.h>
#include <strsafe.h>
#include <ShlObj.h>

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

using namespace std;

//function to enumerate lnk files 
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, _countof(szGotPath), NULL, SLGP_SHORTPATH);

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

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

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

int main(int argc, char** argv[])
{
	

	HRESULT hres = CoInitialize(NULL);
	if(SUCCEEDED(hres))
	{
		TCHAR LinkHold[MAX_PATH] = {0};
		ResolveIt(NULL,TEXT("C:\\Users\\austin\\Desktop\\Pidgin.lnk"),LinkHold,_countof(LinkHold));

		TCOUT << LinkHold << endl;

		CoUninitialize();
	}

	








	
	system("PAUSE");
	return 0;
}
Mar 13, 2012 at 8:53pm
So I ended up with this and I have multi tested it for this weird situation where you can't seem to get a memory buffer size::: CODE::

1
2
3
4
5
6
7
8
9
10
11
12
13
14
TCHAR LinkHold[MAX_PATH] = {0};
		ResolveIt(NULL,TEXT("C:\\Documents and Settings\\fg\\Desktop\\Pidgin.lnk"),LinkHold,_countof(LinkHold));

		TCOUT << LinkHold << endl;
		
		for(int i=0; i<MAX_PATH; i++)
		{
			if(LinkHold[i] < 10000 && LinkHold[i] != 0)
			{
				pidgin += LinkHold[i];

			}

		}


It DOES seem to work ok but I'm not happy with it it seems crappy so any advancements to make solving this problem more efficient would be amazing Thanks Guys. Let me know!
Topic archived. No new replies allowed.