ExpandEnvironmentStrings Not Expanding My Variables - c++

I have a process under the Run key in the registry. It is trying to access an environment variable that I have defined in a previous session. I'm using ExpandEnvironmentStrings to expand the variable within a path. The environment variable is a user profile variable. When I run my process on the command line it does not expand as well. If I call 'set' I can see the variable.
Some code...
CString strPath = "\\\\server\\%share%"
TCHAR cOutputPath[32000];
DWORD result = ExpandEnvironmentStrings((LPSTR)&strPath, (LPSTR)&cOutputPath, _tcslen(strPath) + 1);
if ( !result )
{
int lastError = GetLastError();
pLog->Log(_T( "Failed to expand environment strings. GetLastError=%d"),1, lastError);
}
When debugging Output path is exactly the same as Path. No error code is returned.
What is goin on?

One problem is that you are providing the wrong parameters to ExpandEnvironmentStrings and then using a cast to hide that fact (although you do need a cast to get the correct type out of a CString).
You are also using the wrong value for the last parameter. That should be the size of the output buffer, not the size of the input length (from the documentation the maximum number of characters that can be stored in the buffer pointed to by the lpDst parameter)
Putting that altogether, you want:
ExpandEnvironmentStrings((LPCTSTR)strPath,
cOutputPath,
sizeof(cOuputPath) / sizeof(*cOutputPath));

I don't see any error checking code in your snippet, you don't assert the return value. If there's a problem, you'd never discover it. Also, you are using ANSI strings, beware of the weirdo requirement for the nSize argument (1 extra).

What about buffersize ? Is it initialized - to the right value ?
The documentation states that If the destination buffer is too small to hold the expanded string, the return value is the required buffer size, in characters.

Related

Why does my colon character disappear when I go from char[] to string?

In an old Windows application I'm working on I need to get a path from an environment variable and then append onto it to build a path to a file. So the code looks something like this:
static std::string PathRoot; // Private variable stored in class' header file
char EnvVarValue[1024];
if (! GetEnvironmentVariable(L"ENV_ROOT", (LPWSTR) EnvVarValue, 1024))
{
cout << "Could not retrieve the ROOT env variable" << endl;
return;
}
else
{
PathRoot = EnvVarValue;
}
// Added just for testing purposes - Returning -1
int foundAt = PathRoot.find_first_of(':');
std::string FullFilePath = PathRoot;
FullFilePath.append("\\data\\Config.xml");
The environment value for ENV_ROOT is set to "c:\RootDir" in the Windows System Control Panel. But when I run the program I keep ending up with a string in FullFilePath that is missing the colon char and anything that followed in the root folder. It looks like this: "c\data\Config.xml".
Using the Visual Studio debugger I looked at EnvVarValue after passing the GetEnvironmentVariable line and it shows me an array that seems to have all the characters I'd expect, including the colon. But after it gets assigned to PathRoot, mousing over PathRoot only shows the C and drilling down it says something about a bad ptr. As I noted the find_first_of() call doesn't find the colon char. And when the append is done it only keeps the initial C and drops the rest of the RootDir value.
So there seems to be something about the colon character that is confusing the string constructor. Yes, there are a number of ways I could work around this by leaving the colon out of the env variable and adding it later in the code. But I'd prefer to find a way to have it read and used properly from the environment variable as it is.
You cannot simply cast a char* to a wchar_t* (by casting to LPWSTR) and expect things to work. The two are fundamentally distinct types, and in Windows, they signify different encoding.
You obviously have WinAPI defines set such that GetEnvironmentVariable resolves to GetEnvironmentVariableW, which uses UTF-16 to encode the string. In practice, this means a 0 byte follows every ASCII character in memory.
You then construct a std::string out of this, so it takes the first 0 byte (at char index 1) as the string terminator, so you get just "c".
You have several options:
Use std::wstring and wchar_t EnvVarValue[1024];
Call GetEnvironmentVariableA() (which uses char and ASCII)
Use wchar_t EnvVarValue[1024]; and convert the returned value to a std::string using something like wcstombs.
It seems you are building with wide-character functions (as indicated by your cast to LPWSTR). This means that the string in EnvVarValue is a wide-character string, and you you should be using wchar_t and std::wstring instead.
I would guess that the contents in the array array after the GetEnvironmentVariable call is actually the ASCII values 0x43 0x00 0x3a 0x00 0x5c 0x00 etc. (that is the wide-char representation of "C:\"). The first zero acts as the string terminator for a narrow-character string, which is why the narrow-character string PathRoot only contains the 'C'.
The problem might be that EnvVarValue is not a wchar. Try using wchar_t and std::wstrîng.

How to get temp folder and set a temp file path?

How to get temp folder and set a temp file path? I tried code bellow but it have error. Thank you very much!
TCHAR temp_folder [255];
GetTempPath(255, temp_folder);
LPSTR temp_file = temp_folder + "temp1.txt";
//Error: IntelliSense: expression must have integral or unscoped enum type
This code is adding two pointers.
LPSTR temp_file = temp_folder + "temp1.txt";
It's not concatenating the strings and it's not creating any storage for the resultant string you want.
For C-style strings, use lstrcpy and lstrcat
TCHAR temp_file[255+9]; // Storage for the new string
lstrcpy( temp_file, temp_folder ); // Copies temp_folder
lstrcat( temp_file, T("temp1.txt") ); // Concatenates "temp1.txt" to the end
Based on the documentation for GetTempPath, it would also be wise to replace all occurances of 255 in your code with MAX_PATH+1.
You can't add two character arrays together and get a meaningful result. They're pointers, not a class like std::string which provides such useful operations.
Create a large enough TCHAR array and use GetTempPath, then use strcat to add the file name to it.
TCHAR temp_file [265];
GetTempPath(255, temp_file);
strcat(temp_file, "temp1.txt");
Ideally, you should also test the result of GetTempPath for failure. As far as I can see from the documentation linked in the other answer, the most likely reason for failure is that the path variable supplied is too small. Use MAX_PATH+1+9 as recommended there.

IVdsPack::CreateVolume

HRESULT CreatePartitionEx(ULONGLONG ullOffset, ULONGLONG ullSize, ULONG ulAlign, [in] CREATE_PARTITION_PARAMETERS *para, IVdsAsync **ppAsync
)
When i am passing parameter ppAsync = NULL , perticular call is failing and returned INVALIED argument.
Please help me to solve this issue.
According to the documentation, concerning the last parameter - ppAsync:
The address of an IVdsAsync interface pointer, which VDS initializes
on return. Callers must release the interface. Use this pointer to
cancel, wait for, or query the status of the operation.
This means that you should provide an actual pointer as a last parameter when calling the function. Since you are providing NULL, probably that is causing the problem.
EDIT:
Use like this:
IVdsAsync *pAsync; // Declare a pointer
// Then use it like this (take a look at the last parameter)
CreatePartitionEx(
ullOffset,
ullSize,
ulAlign,
para,
&pAsync); // You pass it with a leading &, which gives you the address of the pointer
And that should do it.
Remember that you should release the pAsync after you are finished with it, as the documentation states.
I am doing the same thing with Createvolume() , buts its returning hResult= E_InvalidArg . The fourth parameter is stripe size .The Windows implementation requires the stripe size to be 65536 if the type is VDS_VT_STRIPE or VDS_VT_PaARITY. Other volume types are not striped and the stripe size is 0.

How to get the path of the exexuter in C++?

I am using Visual studio 2008 and I want to get the absolute path of the .exe file?
meaning when the user opens the exe file, I need to know its absolute path??
thanks in advance
Under Windows try the following:
char ExeName[8192]; // or what ever max. size you expect.
if (0 != GetModuleFileName (NULL, ExeName, sizeof (ExeName)))
{
printf ("Your array was probably not large enough. Call GetLastError for details\n");
}
If you compile for unicode use wchar_t.
Using the _pgmptr or _wpgmptr global variable is probably the easiest way.* (They're in stdlib.h.)
*Note: Under some rather rare circumstances, it's possible that this won't work... in that case, use GetModuleFileName(NULL, ...);
If you want to obtain a path of the current process, you should use API function:
GetModuleFileName
But, if you want to obtain a full path of the process that is not written by you, use
GetModuleFileNameEx
Above function expects one argument more than GetModuleFileName - it is a HANDLE of a process which path is supposed to be obtained. It is explained in more details on MSDN.

Getting GPU clock speeds with SetupDiEnumDeviceInfo

I posted a question earlier regarding obtaining GPU clock speeds, but I guess the thread appeared as already answered since someone had replied to it.
I'd been advised by one of your members to try extracting GPU clock speeds using SetupDiEnumDeviceInfo.
However, I looked around at some examples, like this one: http://www.codeproject.com/KB/system/DevMgr.aspx
and nothing seemed to be displayed about the clock speed.
Could someone please elaborate on how to achieve this, if at all possible?
Thanks again
You will want to check out this msdn article:
http://msdn.microsoft.com/en-us/library/bb742655.aspx
Specifically, follow these steps:
Call SetupDiGetDeviceRegistryProperty to retrieve the size, in bytes, of the property value. Supply the following parameter values:
Set DeviceInfoSet to a handle to a device information set that contains the device instance for which to retrieve the requested property value.
Set DeviceInfoData to a pointer to an SP_DEVINFO_DATA structure that represents the device instance for which to retrieve the requested property value.
Set Property to an SPDRP_Xxx identifier. For a list of these identifiers and a description of the corresponding device properties, see the description of the Property parameter that is included with SetupDiSetDeviceRegistryProperty.
Set PropertyRegDataType to a pointer to a DWORD-typed variable.
Set PropertyBuffer to NULL.
Set PropertyBufferSize to zero.
Set RequiredSize to a pointer to a DWORD-typed variable that receives, the size, in bytes of the property value.
In response to the call to SetupDiSetDeviceRegistryProperty, SetupDiGetDeviceRegistryProperty sets *RequiredSize to the size, in bytes, of the buffer that is required to retrieve the property value, logs the error code ERROR_INSUFFICIENT_BUFFER, and returns FALSE. A subsequent call to GetLastError will return the most recently logged error code.
Call SetupDiGetDeviceRegistryProperty again and supply the same parameter values that were supplied in the first call, except for the following changes:
Set PropertyBuffer to a pointer to a BYTE-typed buffer that receives the requested property value.
Set PropertyBufferSize to the the size, in bytes, of the PropertyBuffer buffer. The first call to SetupDiGetDeviceRegistryProperty retrieved the required size of the PropertyBuffer buffer in *RequiredSize.
This link shows how to get to the point where you've got the required strucutres to call SetupDiGetDeviceRegistryProperty.
http://www.pinvoke.net/default.aspx/setupapi/SetupDiEnumDeviceInfo.html