// C++ with Microsoft extensions

// Это консольное приложение печатает на стандартный вывод дерево папок
// основного пространства имён оболочки Windows.

#define _WIN32_DCOM

#include <objbase.h>
#include <shlobj.h>
#include <string>
#include <iostream>

using namespace std;

// Эта процедура производит вывод строки, попутно
// конвертируя её из кодировки ANSI в кодировку OEM.
void WriteStr(const char * s)
{
  char * s1 = strdup( s );
  CharToOemBuff( s1, s1, strlen(s1) );
  cout << s1;
  free( reinterpret_cast<void *>( s1 ) );
}

// Эта процедура производит вывод указанного
// количества символов, попутно конвертируя их из кодировки ANSI
// в кодировку OEM.
void WriteChar(char ch, size_t count)
{
  CharToOemBuff( &ch, &ch, 1 );
  for(int i=0; i < count; i++) cout << ch;
}

// Эта процедура производит вывод строки, попутно
// конвертируя её из кодировки ANSI в кодировку OEM.
// Эта процедура также добавляет перевод каретки по окончании вывода.
void WritelnStr(const char * s)
{
  WriteStr( s );
  cout << "\n";
}

LPMALLOC pMalloc = NULL;
HRESULT hr;

// Эта процедура интерпретирует содержание структуры STRRET.
// Также она освобождает временные буфера при необходимости, так что
// для её корректной работы требуется наличие объекта pMalloc.
// После завершения работы с возвращаемым именем необходимо освободить буфер
// с помощью процедуры ::free.
char * GetDisplayName( LPCITEMIDLIST pidl,  const STRRET& value )
{
  char * result = NULL;
  switch( value.uType )
  {
  case STRRET_CSTR:
    result = strdup( value.cStr );
    break;
  case STRRET_WSTR:
    {
      int iSize = WideCharToMultiByte( CP_THREAD_ACP, 0, value.pOleStr, -1, NULL, 0, NULL, NULL );
      result = (char *)malloc(iSize);
      WideCharToMultiByte( CP_THREAD_ACP, 0, value.pOleStr, -1, result, iSize, NULL, NULL );
      pMalloc->Free( value.pOleStr );
    }
    break;
  case STRRET_OFFSET:
    result = strdup( PSTR( PBYTE(pidl) + value.uOffset ) );
    break;
  }
  return result;
}

int Level = 0;

// Основная процедура выполняет рекурсивный просмотр структуры папок, начиная с данной.
// Она выводит имена элементов, попутно отслеживая отступы.
void ShowFolder( LPSHELLFOLDER folder )
{
  LPITEMIDLIST pidlChild;
  STRRET Value;
  LPENUMIDLIST Iterator;
  ULONG celtFetched;
  LPSHELLFOLDER child;

  hr = folder->EnumObjects( NULL /* no owner window */, SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN, &Iterator );
  if( SUCCEEDED( hr ) )
  __try
  {
    Level++;
    for(;;)
    {
      hr = Iterator->Next( 1, &pidlChild, &celtFetched );
      if( hr != NOERROR ) break;
      __try
      {
        hr = folder->GetDisplayNameOf( pidlChild, SHGDN_INFOLDER | SHGDN_INCLUDE_NONFILESYS, &Value );
        if( SUCCEEDED( hr ) )
        {
          char * s = GetDisplayName( pidlChild, Value );
          WriteChar( ' ', Level );
          WritelnStr( s );
          free( reinterpret_cast<void *>( s ) );
        }
        hr = folder->BindToObject( pidlChild, NULL, IID_IShellFolder, (void**)&child );
        if( SUCCEEDED( hr ) )
        __try
        {
          ShowFolder( child );
        }
        __finally
        {
          child->Release();
        }
      }
      __finally
      {
        pMalloc->Free( pidlChild );
      }
    }
    Level--;
  }
  __finally
  {
    Iterator->Release();
  }
}

LPSHELLFOLDER desktop = NULL;
ITEMIDLIST itemidlist = { { 0 } };
LPITEMIDLIST pidlItself = & itemidlist; // This pidl now points to an empty Identifier List.
                                        // It is point to owner folder itself.
                                        // NB: It works only for a root folder!
STRRET Value;

// Основное тело программы выполняет необходимую инициализацию, затем
// восстанавливает имя корневой папки, выводит его, и обращается к ShowFolder для выполнения рекурсии.
void main( int argc, char *argv[])
{
  hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
  if( SUCCEEDED( hr ) )
  __try
  {
    hr = SHGetMalloc( &pMalloc );
    if( SUCCEEDED( hr ) )
    __try
    {
      hr = SHGetDesktopFolder( &desktop );
      if( SUCCEEDED( hr ) )
      __try
      {
        hr = desktop->GetDisplayNameOf( pidlItself, SHGDN_NORMAL | SHGDN_INCLUDE_NONFILESYS, &Value );
        if( SUCCEEDED( hr ) )
        {
          char * sTempName = GetDisplayName( pidlItself, Value );
          WritelnStr( sTempName );
          free( reinterpret_cast<void *>(sTempName) );
        }
        ShowFolder( desktop );
      }
      __finally
      {
        desktop->Release();
      }
    }
    __finally
    {
      pMalloc->Release();
    }
  }
  __finally
  {
    CoUninitialize();
  }
}
// Delphi

program ShellA;

// Это консольное приложение печатает на стандартный вывод дерево папок
// основного пространства имён оболочки Windows.

uses
  Windows, ActiveX, ShlObj;

{$APPTYPE CONSOLE}

// Эта процедура производит вывод строки, попутно
// конвертируя её из кодировки ANSI в кодировку OEM.
procedure WriteStr(s: string);
begin
  UniqueString( s );
  CharToOemBuff( PChar(s), PChar(s), Length(s) );
  Write(s);
end;

// Эта процедура производит вывод указанного
// количества символов, попутно конвертируя их из кодировки ANSI
// в кодировку OEM.
procedure WriteChars(Ch: char; Count: Integer);
var
  s: string;
begin
  CharToOemBuff( @Ch, @Ch, 1 );
  s := StringOfChar(Ch, Count);
  Write( s );
end;

// Эта процедура производит вывод строки, попутно
// конвертируя её из кодировки ANSI в кодировку OEM.
// Эта процедура также добавляет перевод каретки по окончании вывода.
procedure WritelnStr(const s: string);
begin
  WriteStr( s + #13#10 );
end;

var
  pMalloc: IMalloc;
  hr: HRESULT;

// Эта процедура интерпретирует содержание структуры STRRET.
// Также она освобождает временные буфера при необходимости, так что
// для её корректной работы требуется наличие объекта pMalloc.
function GetDisplayName( pidl: PItemIDList; const Value: STRRET ): string;
begin
  with Value do
  case uType of
    STRRET_CSTR: Result := PChar(@cStr[0]);
    STRRET_WSTR:
    begin
      Result := pOleStr;
      pMalloc.Free( pOleStr );
    end;
    STRRET_OFFSET: Result := PChar( LongWord(pidl) + uOffset );
  end;
end;

var
  Level: Integer;

// Основная процедура выполняет рекурсивный просмотр структуры папок, начиная с данной.
// Она выводит имена элементов, попутно отслеживая отступы.
procedure ShowFolder(folder: IShellFolder);
var
  pidlChild: PItemIDList;
  Value: STRRET;
  Iterator: IEnumIDList;
  celtFetched: ULONG;
  child: IShellFolder;
begin
  hr := folder.EnumObjects( 0 (* no owner window *), SHCONTF_FOLDERS or SHCONTF_INCLUDEHIDDEN, Iterator );
  if Succeeded( hr ) then
  try
    Inc(Level);
    while true do
    begin
      hr := Iterator.Next( 1, pidlChild, celtFetched );
      if hr <> NOERROR then Break;
      try
        hr := folder.GetDisplayNameOf( pidlChild, SHGDN_INFOLDER or SHGDN_INCLUDE_NONFILESYS, Value );
        if Succeeded( hr ) then
        begin
          WriteChars( ' ', Level );
          WritelnStr( GetDisplayName( pidlChild, Value ) );
        end;
        hr := folder.BindToObject( pidlChild, nil, IID_IShellFolder, Pointer(child) );
        if Succeeded( hr ) then
        try
          ShowFolder( child );
        finally
          child := nil;
        end;
      finally
        pMalloc.Free( pidlChild );
      end;
    end;
    Dec(Level);
  finally
    Iterator := nil;
  end;
end;

var
  desktop: IShellFolder;
  mkid: SHITEMID;
  pidlItself: PItemIDList;
  Value: STRRET;

// Основное тело программы выполняет необходимую инициализацию, затем
// восстанавливает имя корневой папки, выводит его, и обращается к ShowFolder для выполнения рекурсии.
begin
  Level := 0;
  mkid.cb := 0;
  pidlItself := @mkid; // This pidl now points to an empty Identifier List. It is points to owner folder itself.
                       // NB: It works only for a root folder!
  hr := CoInitializeEx( nil, COINIT_MULTITHREADED );
  if Succeeded( hr ) then
  try
    hr := SHGetMalloc( pMalloc );
    if Succeeded( hr ) then
    try
      hr := SHGetDesktopFolder( desktop );
      if Succeeded( hr ) then
      try
        hr := desktop.GetDisplayNameOf( pidlItself, SHGDN_NORMAL or SHGDN_INCLUDE_NONFILESYS, Value );
        if Succeeded( hr ) then
        begin
          WritelnStr( GetDisplayName( pidlItself, Value ) );
        end;
        ShowFolder( desktop );
      finally
        desktop := nil;
      end;
    finally
      pMalloc := nil;
    end;
  finally
    CoUninitialize;
  end;
end.