Will CString's ReleaseBuffer release Shell Allocated CoTaskMemAlloc String? - c++

I believe, from viewing this article, I can safely use CStrings to store the returned string results of certain Windows API functions.
For example, I can do the following (not my code, from the article I linked above):
//GetCurrentDirectory gets LPTSTR
CString strCurDir;
::GetCurrentDirectory(MAX_PATH, strCurDir.GetBuffer(MAX_PATH));
strCurDir.ReleaseBuffer();
GetCurrentDirectory allocates the data in the "regular" way. I know I could also use an STL wstring to do this as well.
Now my question is, can I safely do this?
int main()
{
CString profileRootPath;
HRESULT result = SHGetKnownFolderPath(FOLDERID_Profile, 0, nullptr, (PWSTR*)&profileRootPath);
wcout << profileRootPath.GetString();
profileRootPath.ReleaseBuffer();
Sleep(10000);
return 0;
}
According to SHGetKnownFolderPath's MSDN page, the data output by SHGetKnownFolderPath needs to be de-allocated with a call to CoTaskMemFree. Is the call to ReleaseBuffer invalid because of this? Or will that work properly? Is it not a good idea to use any string class in this case and just use a plain C style array to hold the data, and then use CoTaskMemFree on the array? If the code is invalid, what is the most correct way to do this?

With ATL the code snippet might be as simple as:
CComHeapPtr<WCHAR> pszPath;
HRESULT result = SHGetKnownFolderPath(FOLDERID_Profile, 0, nullptr, (PWSTR*) &pszPath);
CString sPath(pszPath);
wcout << sPath.GetString();
~CComHeapPtr will do CoTaskMemFree going out of scope, and CString constructor will take the value as const WCHAR*.
Without CComHeapPtr you can do it like this:
WCHAR* pszPath = nullptr;
HRESULT result = SHGetKnownFolderPath(FOLDERID_Profile, 0, nullptr, (PWSTR*) &pszPath);
CString sPath(pszPath);
CoTaskMemFree(pszPath);
wcout << sPath.GetString();
GetCurrentDirectory simply takes your memory pointer to store the string to, so it makes sense to use stack variable because it has zero initialization and cleanup cost. If you need a string, you can build it from stack character array - this eliminates necessity in ReleaseBuffer call:
TCHAR pszPath[MAX_PATH];
GetCurrentDirectory(_countof(pszPath), pszPath);
CString sPath(pszPath);

The answer to my question is simply no, which I figured it would be, since CoTaskMemAlloc is a special way to allocate memory. I'll just stick with the regular way to do things.
int main()
{
WCHAR* profileRootPath = nullptr;
HRESULT result = SHGetKnownFolderPath(FOLDERID_Profile, 0, nullptr, &profileRootPath);
wcout << profileRootPath;
CoTaskMemFree(profileRootPath);
Sleep(10000);
return 0;
}

Related

Convert CComPtr<IShelltem2> to LPWSTR*?

I'm using a variable of type CComPtr and I need to modify a LPWSTR* variable. The function I use extracts metadata about file description for executable files. I am not sure about how I should allocate memory for the LPWSTR* and how to change its value to the one of the CComPtr. lpszFileDesc must get the value of description.
BOOL ExeDescription(LPWSTR* lpszFileDesc, LPCWSTR filePath)
{
CComPtr<IShellItem2> item;
HRESULT hr = CoInitialize(nullptr);
*lpszFileDesc = NULL;
BOOL fResult = TRUE;
hr = SHCreateItemFromParsingName(filePath, nullptr, IID_PPV_ARGS(&item));
if (FAILED(hr))
{
fResult = FALSE;
}
else
{
CComPtr<WCHAR> description;
hr = item->GetString(PKEY_FileDescription, &description);
if (FAILED(hr))
{
fResult = FALSE;
}
else
{
if (!description)
{
*lpszFileDesc = PathFindFileNameW(filePath);
}
else
{
// here I want to copy the contents of description
// into lpszFileDesc but I don't know how
}
if (!*lpszFileDesc)
{
fResult = FALSE;
}
}
}
CoUninitialize();
return fResult;
}
Also, when I call this function how do I deallocate the memory for lpszFileDesc after calling the function?
For example if in wmain() I have:
LPWSTR* lpszFileDesc;
ExeDescription(LPWSTR* lpszFileDesc, LPCWSTR filePath);
How do I deallocate the memory if I don't need the file description after that?
Basic Errors
HRESULT hr = CoInitialize(nullptr);
...
CoUninitialize();
COM should be initialized only once at startup of the thread, because it defines the concurrency model of the thread (amongst other things). It's not up to your function to decide how COM will be initialized for the thread. Once COM is initialized for a thread, subsequent calls to CoInitialize[Ex] within that thread will fail anyway. So remove this code and put it into WinMain or the main function of the thread where you are using COM.
CComPtr<WCHAR> description;
Using CComPtr is wrong here, because IShellItem2::GetString() does not return an interface, but a simple C string. Such "raw" memory allocated by COM API must be freed using CoTaskMemFree(), which can be automated by using CComHeapPtr.
Preferred solution - change the interface
how do I deallocate the memory for lpszFileDesc
Do yourself a favor and use std::wstring instead of raw C string pointer to return a string from your function. The std::wstring destructor takes care of deallocation automatically. Manually managing the memory of C strings is too cumbersome and error-prone. When someone else reads your code and sees std::wstring, there will be no question about how the memory is managed.
I suggest to change your interface like this:
BOOL ExeDescription(std::wstring& fileDesc, LPCWSTR filePath);
... and the assignment within the function body becomes:
if (!description)
{
fileDesc = PathFindFileNameW(filePath);
}
else
{
fileDesc = description;
}
CComHeapPtr<WCHAR> has a conversion operator to WCHAR*, that's why the assignment to std::wstring simply works.
Call the function like this:
std::wstring fileDesc;
ExeDescription(fileDesc, filePath);
// No worries about deallocation of fileDesc!
Solution using original interface
That being said, here is a solution using your original interface. You can either use the COM allocator, as IShellItem2::GetString() already uses it (and there will be no copying in the common case) or use a different allocator (then you always have to copy). In both cases, the caller is responsible to call the right deallocation function, which you have to document (another reason why I would prefer the std::wstring solution).
Example of using the COM allocator:
BOOL ExeDescription(LPWSTR* lpszFileDesc, LPCWSTR filePath)
{
// ... other code ...
// GetString() uses CoTaskMemAlloc() internally
hr = item->GetString(PKEY_FileDescription, lpszFileDesc);
// ... other code ...
if (! *lpszFileDesc )
{
LPCWSTR fileName = PathFindFileNameW(filePath);
// Allocate buffer using the COM allocator and copy fileName to it.
std::size_t const len = wcslen(fileName);
*lpszFileDesc = reinterpret_cast<LPWSTR>(CoTaskMemAlloc(len * sizeof(WCHAR)));
if(*lpszFileDesc)
wcscpy_s(*lpszFileDesc, len, fileName);
}
// ... more code ...
}
Usage at the caller site:
LPWSTR fileDesc = nullptr;
ExeDescription(&fileDesc, filePath);
// ... use fileDesc ...
CoTaskMemFree(fileDesc);
Simplified usage with CComHeapPtr:
CComHeapPtr<WCHAR> fileDesc;
ExeDescription(&fileDesc, filePath);
// ... use fileDesc ...
// Deallocation happens automatically through CComHeapPtr's destructor

How to return a string from a C++ DLL into a MetaTrader 4 code-execution ecosystem?

I have following function
__declspec(dllexport) wchar_t* __stdcall __getJson(wchar_t * listN){
setlocale(LC_ALL, "");
//function logic
wstring ant = utf8_to_wstring(result);
const WCHAR* constRes = ant.c_str();
WCHAR* tempObj=new WCHAR[ant.length()];
wcscpy(tempObj, constRes);
thread Thread([tempObj]{
Sleep(1000);
delete[] tempObj;
});
Thread.detach();
return tempObj;
}
This DLL returns wchar_t* to MetaTrader4.
I tried many ways to return correct value and avoid memory leaks such as set return type const wchar_t*, creating my own class with destructor with delete[] in. But all this attempts was unsuccessful: I got '??ello' instead of 'hello'. Just first one or two symbols were incorrect. With creating thread it works right. But, I want to know, may there be better solution?
Another way of doing that (a little bit simpler, but for some cases only):
//C++
extern "C" __declspec(dllimport) const wchar_t *GetMessage();
const wchar_t *GetMessage()
{
static std::wstring last_message;
last_message = GetSomeMessage();
return last_message.c_str();
}
//MQL
#import "MyDll.dll"
string GetMessage();
#import
string message = GetMessage();
To create a string in your DLL and pass it to the caller, you must dynamically allocate some memory in the DLL to store the string's characters, and pass a pointer to that memory to the caller.
Moreover, the caller must be able to release that memory when the string is not needed anymore.
To make it work properly, you must use the same memory manager/allocator to both allocate and free the string's memory.
One option would be to use a common system-wide allocator like the COM allocator. In this way, you can allocate the memory in the DLL using CoTaskMemAlloc, and the caller can free it using the matching CoTaskMemFree.
Another option would be to return a BSTR string, allocated with SysAllocString in the DLL. And the caller would release that string invoking SysFreeString.
Or, you could provide a custom function to free the string's memory in your DLL. For example, you could allocate the string's memory in your DLL using new[], and you could provide a MyDllFreeString function that invokes delete[].
Note that, when you allocate memory for a C-style string, you must consider an additional slot for the string's NUL-terminator (so, you must allocate stringLength + 1 wchar_ts).
#ol' ASM hackers always used to start with#assume nothing ; mql4_string != string
Bingo, the headbang is evident. Receiving side does not assume, since New-MQL4.56789 was introduced, it's representation of a block of bytes as a string, but a struct (!).
(cit.:) Internal representation of the string type is a structure of 12 bytes long:
#pragma pack(push,1)
struct MqlString
{
int size; // 32-bit integer, contains size of the buffer, allocated for the string.
LPWSTR buffer; // 32-bit address of the buffer, containing the string.
int reserved; // 32-bit integer, reserved.
};
#pragma pack(pop,1)
(cit.:) ( MQL4-side doc: )String Type
The string type is used for storing text strings. A text string is a sequence of characters in the Unicode format with the final zero at the end of it.
Accidentaly, I put my mind to BOOL APIENTRY DllMain. So it solve my problem without creating threads.
vector<wchar_t*> tempObjVector;
BOOL APIENTRY DllMain(HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
while (tempObjVector.size() != 0)
{
delete[] tempObjVector.back();
tempObjVector.pop_back();
}
break;
}
return TRUE;
}
__declspec(dllexport) wchar_t* __stdcall __getJson(wchar_t * listN){
....
....
wchar_t* tempObj=new wchar_t[ant.length()+1];
tempObj[ant.length()] = 0;
wcscpy(tempObj, constRes);
tempObjVector.push_back(tempObj);
return tempObj;
}

Init std::string with single copy

I have the following code in C++ on Win32. It's simply a C++ warp on some Win32 API that returns a CHAR *:
wstring expandEnvironmentVariables(const wstring & str)
{
DWORD neededSize = ExpandEnvironmentStrings(str.c_str(), nullptr, 0);
vector<WCHAR> expandedStr(neededSize);
if (0 == ExpandEnvironmentStrings(str.c_str(), expandedStr.data(), static_cast<DWORD>(expandedStr.size()))) {
return wstring(str);
}
return wstring(expandedStr.data());
}
What bothers me about this code, is the double copy of the result.
by the API into a vector of WCHARs.
from the vector into std::wstring.
Is there a way to implement this code with just a single copy, and without a major change to the signature of the function.
This is a specific example, but I'm more interested in the general solution and the right way to work with std::wstring/std::string, because this pattern shows itself in many places in the code.
Regarding the C++ side you can just use a wstring directly as a result variable.
To get a pointer to the buffer of a wstring of non-zero size, just use &s[0].
Just like std::vector, std::basic_string has a guaranteed contiguous buffer.
For the return it will probably get Return Value Optimization (RVO), and if not then it will be moved.
Disclaimer: I haven't checked the documentation of the API functions. I do not know if this code correct or even meaningful. I'm just assuming that.
wstring expandEnvironmentVariables(const wstring & str)
{
wstring expandedStr;
DWORD neededSize = ExpandEnvironmentStrings(str.c_str(),
nullptr, 0);
if (neededSize)
{
expandedStr.resize(neededSize);
if (0 == ExpandEnvironmentStrings(str.c_str(),
&expandedStr[0],
neededSize))
{
// pathological case requires a copy
expandedStr = str;
}
}
// RVO here
return expandedStr;
}
EDIT:
On reflection, since we're using c++ let's go the whole hog and put in proper error detection and report errors with an informative nested exception chain:
DWORD check_not_zero(DWORD retval, const char* context)
{
if(!retval)
throw std::system_error(GetLastError(),
std::system_category(),
context);
return retval;
}
std::wstring expandEnvironmentVariables(const std::wstring & str)
try
{
DWORD neededSize = check_not_zero(ExpandEnvironmentStrings(str.c_str(),
nullptr,
0),
"ExpandEnvironmentStrings1");
std::wstring expandedStr(neededSize, 0);
check_not_zero(ExpandEnvironmentStrings(str.c_str(),
&expandedStr[0],
neededSize),
"ExpandEnvironmentStrings2");
// RVO here
return expandedStr;
}
catch(...)
{
std::throw_with_nested(std::runtime_error("expandEnvironmentVariables() failed"));
}

Pass char[N] param to thread

i have a variable declared as
char myvariable[N] = "blablabla"
and i need to pass it to a thread
DWORD MyThread(LPVOID lpdwParam)
i tried to cast inside the thread function the lpdwParam in char* but it doesn't work. How can i fix it?
EDIT 1
Here the complete part of code
char myvariable[16];
GetDlgItemTextA(hDlg, IDC_IPADDRESS, &myvariable[0], 16);
myThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MyThread, (LPVOID)&myvariable, 0, &myThreadId);
DWORD MyThread(LPVOID lpdwParam)
{
char *myvariable2 = (char *)lpdwParam;
....
}
EDIT 2
Doesn't work means that myvariable2 doesn't contains the text of myvariable
EDIT 3
char *myvariable = new char[16];
GetDlgItemTextA(hDlg, IDC_IPADDRESS, myvariable, 16);
myThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MyThread, (LPVOID)myvariable, 0, &myThreadId);
and the thread function:
char *myvariable2 = (char *)lpdwParam;
If you're doing something like this:
// ...
char myvariable[N] = "blablabla";
HANDLE hThread=CreateThread(NULL, 0, MyThread, (LPVOID)myvariable, 0); // however you should use beginthread to avoid troubles with the CRT
// ...
DWORD MyThread(LPVOID lpdwParam)
{
char * mystring = (char *)lpdwParam;
// ...
return 0;
}
and you don't get the correct characters by reading mystring, my guess is that, being myvariable allocated on the stack, it goes out of scope before MyThread gets the chance to run, thus you get the same kind of problems you encounter when you return a pointer to a local variable.
The solution would be to allocate dynamically your string:
// ...
char * myvariable = new char[N];
*myvariable=0;
strncat(myvariable, "blablabla", N); // this is equivalent to what the nonstandard strlcpy would do
HANDLE hThread=CreateThread(NULL, 0, MyThread, (LPVOID)myvariable, 0); // however you should use beginthread to avoid troubles with the CRT
// ...
DWORD MyThread(LPVOID lpdwParam)
{
char * mystring = (char *)lpdwParam;
// ...
// when you're done with mystring, remember to free it; even better, use a smart pointer
delete [] mystring;
// ...
return 0;
}
By the way, notice that, as already said in the snippets, if you plan to use CRT functions inside your newly created thread you shouldn't use CreateThread directly, but you should instead use the _beginthread/_beginthreadex functions, because otherwise some CRT per-thread structures may not get initialized correctly.
Addendum
i edited my code to use new char[16] but it doesn't work. When i cast the variable from LPVOID to char* inside the thread function i get only strange symbols
If you changed the code so that myvariable is now a pointer, you should remove the & from the call to CreateThread; & was superfluous when it was used with the array (in that case just using its name was enough), but now that myvariable is a pointer it is plain wrong, since using it on myvariable will provide the address of myvariable instead of the address stored in myvariable.
Long story short, remove that ampersand.
If your doing c++ casting, you will need to use const char* var = reinterpret_cast<const char*>(lpdwParam);. Just be careful though, if its a stack string, it'll probably pass out of scope before the thread uses it, if its a static string, you should use const to preventing any accidental overwriting of data

Can I use a static var to "cache" the result? C++

I am using a function that returns a char*, and right now I am getting the compiler warning "returning address of local variable or temporary", so I guess I will have to use a static var for the return, my question is can I make something like if(var already set) return var else do function and return var?
This is my function:
char * GetUID()
{
TCHAR buf[20];
StringCchPrintf(buf, 20*sizeof(char), TEXT("%s"),
someFunction());
return buf;
}
And this is what I want to do:
char * GetUID()
{
static TCHAR buf[20];
if(strlen(buf)!=0) return buf;
StringCchPrintf(buf, 20*sizeof(char), TEXT("%s"),
someFunction());
return buf;
}
Is this a well use of static vars? And should I use ZeroMemory(&buf, 20*sizeof(char))? I removed it because if I use it above the if(strlen...) my TCHAR length is never 0, should I use it below?
The reason you're getting a warning is because the memory allocated within your function for buf is going to be popped off the stack once the function exits. If you return a pointer to that memory address, you have a pointer to undefined memory. It may work, it may not - it's not safe regardless.
Typically the pattern in C/C++ is to allocate a block of memory and pass a pointer to that block into your function. e.g.
void GetUID( char* buf )
{
if(strlen(buf)!=0) return;
StringCchPrintf(buf, 20*sizeof(char), TEXT("%s"), someFunction());
}
If you want the function (GetUID) itself to handle caching the result, then you can use a static, a singleton (OOP), or consider thread local storage.
(e.g. in Visual C++)
__declspec(thread) TCHAR buf[20];
It's OK if your code is single threaded. The buffer will be set to contain all zeros when the function is entered for the very first time, so there is no need to explicitly set its contents to zero. But these days all code eventually tends to become multi-threaded, so I would not do this, if I were you.
What you should do instead is allocate buf dynamically using new, and then return it. But be aware that the caller would be responsible for deallocating the memory.
Better yet, use std::string instead of char *.
You could do that, but it won't be thread-safe. You should also be careful with what you do with the result, since you can not store it between subsequent calls to the function (without copying it, of course).
You should also initialize the static variable to the empty string.
This is how I would do it.
It caches; it does not rely on the buffer being 0.
It does have the implicit assumption that 'buf' will be identical from thread to thread, which is not (to my knowledge) correct. I would use a global for that purpose.
//returns a newly allocated buffer, every time. remember to delete [] it.
char * GetUID()
{
static TCHAR buf[20];
static bool run = false;
TCHAR ret_mem = new TCHAR[20];
if(run)
{ return ret_mem; }
//do stuff to the buf
//assuming - dst, src, size.
memcpy(ret_mem, buf, 20);
run = true;
return ret_mem;
}