Thread View: borland.public.cppbuilder.nativeapi
7 messages
7 total messages
Started by Kris
Thu, 13 Mar 2008 08:56
Cleaning up after using GetDisplayNameOf()
Author: Kris
Date: Thu, 13 Mar 2008 08:56
Date: Thu, 13 Mar 2008 08:56
47 lines
2312 bytes
2312 bytes
Hi,
I'm using GetDisplayNameOf() to obtain the (localized) display name of
the MyDocuments folder (i.e. CSIDL_PERSONAL).
This was somewhat confusing to implement, but I managed to get it
working properly. However, I am unsure if I'm doing a proper clean-up
after I'm finished ?
I'm especially concerned about the STRRET info at
http://msdn2.microsoft.com/en-us/library/bb759820(VS.85).aspx that states:
pOleStr:
A pointer to the string. This memory must be allocated with
CoTaskMemAlloc. It is the calling application's responsibility to free
this memory with CoTaskMemFree when it is no longer needed.
Do I have to take care of freeing that memory, or is someone else taking
care of freeing the STRRET.pOleStr (e.g. pDesktopFolder) ?
Please feel free to mention any other (clean-up) issues that you might
notice with the code sample below.
Thanks,
Kris
CoInitialize(0) ;
LPITEMIDLIST pidl;
STRRET sName;
LPSHELLFOLDER pDesktopFolder;
if(SUCCEEDED(SHGetSpecialFolderLocation(NULL,CSIDL_PERSONAL,&pidl)))
{
if(SUCCEEDED(SHGetDesktopFolder(&pDesktopFolder)))
{
if(SUCCEEDED(pDesktopFolder->GetDisplayNameOf(pidl,SHGDN_INFOLDER,&sName)))
{
// Probably safe to assume STRRET_WSTR is set in this specific case
// So simply use the pOleStr member without any additional checks
WideString DisplayName=sName.pOleStr;
DEBUG("DisplayNameof(CSIDL_PERSONAL)=[%s]",String(DisplayName).c_str());
}
pDesktopFolder->Release();
}
CoTaskMemFree((void*)pidl);
}
CoUninitialize();
Re: Cleaning up after using GetDisplayNameOf()
Author: Darko Miletic
Date: Thu, 13 Mar 2008 13:23
Date: Thu, 13 Mar 2008 13:23
138 lines
5091 bytes
5091 bytes
> Do I have to take care of freeing that memory, or is someone else taking
> care of freeing the STRRET.pOleStr (e.g. pDesktopFolder) ?
Yes you do as stated in documentation.
>
> Please feel free to mention any other (clean-up) issues that you might
> notice with the code sample below.
>
> Thanks,
>
> Kris
First of all if your app is VCL CoInitialize is not needed. By default
COM is initialized in VCL app.
I would never assume anything in API. You should always check uType to
see what is the appropriate action. Also for safety reasons it would be
good to use RAII idiom to handle resource cleanup properly.
Here is my version of the same thing. It is longer and uses only
standard C and C++ library together with Windows API hence it is console
app.
The only thing that can be removed in VCL app is use of ole_init.
//---------------------------------------------------------------------------
#include <windows.h>
#include <shlobj.h>
#include <cstdlib>
#include <string>
#include <vector>
#include <iostream>
#pragma comment(lib,"shell32.lib")
//---------------------------------------------------------------------------
struct ole_init {
ole_init(void) : _isinit(false) {
_isinit = SUCCEEDED(::CoInitialize(NULL));
}
~ole_init(void) {
if (_isinit) {
_isinit = false;
::CoUninitialize();
}
}
bool init_ok(void) const { return _isinit; }
private:
bool _isinit;
};
std::wstring string2wstring (const std::string& str) {
std::wstring result;
if (!str.empty()) {
std::vector<wchar_t> buffer(str.size());
std::size_t res = std::mbstowcs(&buffer[0],str.c_str(),str.size());
if (res > 0) {
result.assign(buffer.begin(),buffer.end());
}
}
return result;
}
struct pidl_holder {
explicit pidl_holder(int folder) : _pidl(NULL) {
LPITEMIDLIST ppidl = NULL;
HRESULT hr = ::SHGetSpecialFolderLocation(NULL,folder,&ppidl);
if (SUCCEEDED(hr)) {
_pidl = ppidl;
}
}
~pidl_holder(void) { release(); }
LPITEMIDLIST ptr(void) {return _pidl;}
private:
LPITEMIDLIST _pidl;
void release(void) {
if (NULL != _pidl) {
::CoTaskMemFree(_pidl);
_pidl = NULL;
}
}
};
struct shdesktop_folder {
shdesktop_folder(void) : _desktop_folder(NULL) {
LPSHELLFOLDER df = NULL;
if (SUCCEEDED(::SHGetDesktopFolder(&df))) {
_desktop_folder = df;
}
}
~shdesktop_folder(void) {
if (NULL != _desktop_folder) {
_desktop_folder->Release();
_desktop_folder = NULL;
}
}
LPSHELLFOLDER ptr(void) { return _desktop_folder; }
private:
LPSHELLFOLDER _desktop_folder;
};
std::wstring get_display_name(void) {
ole_init ol;
std::wstring result;
if (ol.init_ok()) {
pidl_holder pidlobj(CSIDL_PERSONAL);
LPITEMIDLIST pidl = pidlobj.ptr();
if (NULL != pidl) {
shdesktop_folder deskFolder;
LPSHELLFOLDER pDesktopFolder = deskFolder.ptr();
if (NULL != pDesktopFolder) {
STRRET sname = {};
HRESULT hr = pDesktopFolder->GetDisplayNameOf( pidl
,SHGDN_INFOLDER
,&sname);
if (SUCCEEDED(hr)) {
if (sname.uType == STRRET_WSTR) {
result = sname.pOleStr;
::CoTaskMemFree(sname.pOleStr);
sname.pOleStr = NULL;
} else if (sname.uType == STRRET_CSTR) {
result = string2wstring(sname.cStr);
} //else here add the third case code
}
}
}
}
return result;
}
int main(int /*argc*/, char** /*argv[]*/)
{
std::wcout << get_display_name() << std::endl;
return EXIT_SUCCESS;
}
//---------------------------------------------------------------------------
Re: Cleaning up after using GetDisplayNameOf()
Author: Remy Lebeau (TeamB)
Date: Thu, 13 Mar 2008 16:37
Date: Thu, 13 Mar 2008 16:37
13 lines
1444 bytes
1444 bytes
"Darko Miletic" <kiklop@fibertel.com.ar> wrote in message news:47d92ad2@newsgroups.borland.com... > First of all if your app is VCL CoInitialize is not needed. > By default COM is initialized in VCL app. There is no harm in doing it yourself, though. The COM library is reference counted. As long as all calls to CoInitialize() have balanced calls to CoUnitialize(), you will be fine. Gambit
Re: Cleaning up after using GetDisplayNameOf()
Author: Remy Lebeau (TeamB)
Date: Thu, 13 Mar 2008 16:45
Date: Thu, 13 Mar 2008 16:45
73 lines
3028 bytes
3028 bytes
"Kris" <x@x.com> wrote in message news:47d8ec90$1@newsgroups.borland.com...
> Do I have to take care of freeing that memory
Yes.
> is someone else taking care of freeing the STRRET.pOleStr
> (e.g. pDesktopFolder) ?
No.
> Probably safe to assume STRRET_WSTR is set in this specific case
> So simply use the pOleStr member without any additional checks
You cannot assume that. You need to look at the STRRET's uType parameter to
know exactly how to interpret the STRRET's contents properly, for example:
switch( sName.uType )
{
case STRRET_CSTR
DEBUG("DisplayNameof(CSIDL_PERSONAL)=[%s]", sName.cStr);
break;
case STRRET_OFFSET:
{
char *pName = (char*)(((LPBYTE)pidl) + sName.uOffset);
DEBUG("DisplayNameof(CSIDL_PERSONAL)=[%s]", pName);
break;
}
case STRRET_WSTR:
{
// assuming DEBUG() is based on printf() or similar function...
DEBUG("DisplayNameof(CSIDL_PERSONAL)=[%ls]", sName.pOleStr);
CoTaskMemFree(sName.pOleStr);
break;
}
}
Alternatively, you can use one of the StrRetTo...() functions instead, which
also handle freeing the STRRET_WSTR memory for you, ie:
TCHAR szBuf[MAX_PATH+1] = {0};
StrRetToBuf(&sName, pidl, szBuf, MAX_PATH+1);
#ifdef UNICODE
DEBUG("DisplayNameof(CSIDL_PERSONAL)=[%ls]", szBuf);
#else
DEBUG("DisplayNameof(CSIDL_PERSONAL)=[%s]", szBuf);
#endif
Or:
LPTSTR pName;
StrRetToStr(&sName, pidl, &pName);
#ifdef UNICODE
DEBUG("DisplayNameof(CSIDL_PERSONAL)=[%ls]", szBuf);
#else
DEBUG("DisplayNameof(CSIDL_PERSONAL)=[%s]", szBuf);
#endif
CoTaskMemFree(pName);
Or:
WideString wName;
StrRetToBSTR(&sName, pidl, &wName);
DEBUG("DisplayNameof(CSIDL_PERSONAL)=[%ls]", wName.c_bstr());
Gambit
Re: Cleaning up after using GetDisplayNameOf()
Author: Darko Miletic
Date: Thu, 13 Mar 2008 17:20
Date: Thu, 13 Mar 2008 17:20
13 lines
1765 bytes
1765 bytes
Remy Lebeau (TeamB) wrote: > "Darko Miletic" <kiklop@fibertel.com.ar> wrote in message > news:47d92ad2@newsgroups.borland.com... > >> First of all if your app is VCL CoInitialize is not needed. >> By default COM is initialized in VCL app. > > There is no harm in doing it yourself, though. The COM library is reference > counted. As long as all calls to CoInitialize() have balanced calls to > CoUnitialize(), you will be fine. You are right but I was just saying that if it is already there no need to add more code than needed.
Re: Cleaning up after using GetDisplayNameOf()
Author: Remy Lebeau (TeamB)
Date: Thu, 13 Mar 2008 17:43
Date: Thu, 13 Mar 2008 17:43
14 lines
1608 bytes
1608 bytes
"Darko Miletic" <kiklop@fibertel.com.ar> wrote in message news:47d96258$1@newsgroups.borland.com... > You are right but I was just saying that if it is already > there no need to add more code than needed. On the other hand, it is not good practice to assume what the framework does internally. The VCL calls CoInitialize/Ex() at startup only when certain units (namely - ComObj, DBTables, HTTPIntr, ScktMain, SConnect, and VCLCom) are being used by the project. Gambit
Re: Cleaning up after using GetDisplayNameOf()
Author: Kris
Date: Fri, 14 Mar 2008 09:02
Date: Fri, 14 Mar 2008 09:02
6 lines
1200 bytes
1200 bytes
Thank you once again for a very comprehensive and complete answer. And yes, simply assuming STRRET_WSTR was quite lazy on my part :-) Regards, Kris
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads