🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.nativeapi
Article #475

Re: Cleaning up after using GetDisplayNameOf()

#475
From: Darko Miletic
Date: Thu, 13 Mar 2008 13:23
138 lines
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;
}
//---------------------------------------------------------------------------
Technical Details
Message-ID: <47d92ad2@newsgroups.borland.com>
Path: arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!proxad.net!feeder1-2.proxad.net!194.25.134.126.MISMATCH!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail
References: <47d8ec90$1@newsgroups.borland.com>

Show Full Headers
Complete Article Headers
X-Google-Thread: 10cc67,b8d31d04a1ebb7b9
X-Google-Attributes: gid10cc67,public,usenet
X-Google-Language: ENGLISH,ASCII-7-bit
Date: Thu, 13 Mar 2008 11:23:16 -0200
From: Darko Miletic <kiklop@fibertel.com.ar>
Reply-To: Darko Miletic <kiklop@fibertel.com.ar>
User-Agent: Thunderbird 2.0.0.12 (Windows/20080213)
MIME-Version: 1.0
Newsgroups: borland.public.cppbuilder.nativeapi
Subject: Re: Cleaning up after using GetDisplayNameOf()
References: <47d8ec90$1@newsgroups.borland.com>
In-Reply-To: <47d8ec90$1@newsgroups.borland.com>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
X-Antivirus: avast! (VPS 080313-0, 13/03/2008), Outbound message
X-Antivirus-Status: Clean
NNTP-Posting-Host: 200.49.157.165
Message-ID: <47d92ad2@newsgroups.borland.com>
X-Trace: newsgroups.borland.com 1205414610 200.49.157.165 (13 Mar 2008 06:23:30 -0700)
Lines: 138
Path: arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!proxad.net!feeder1-2.proxad.net!194.25.134.126.MISMATCH!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail