Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Правильно получить информацию о дисках


Автор: Router 29.3.2009, 12:47
Нужно получить список дисков и их метки, так как они показаны в проводнике.

Получить доступные диски не проблема.
Код

function get_system_drives() : shortstring;
var Drives : set of 0..25;
    i : byte;
begin
  result := '';
  integer(Drives) := GetLogicalDrives;
  for i := 0 to 25 do
    if i in Drives then
      result := result + chr(i + 65) + ' ';
end;

а вот метку у меня не получается получить. Использую функцию GetVolumeInformation.
Код

function GetVolumeLable(Drive : char) : shortstring;
var
  VolName, FileSysName: array [0..255] of char;
  MaxCompLength, FileSysFlags : cardinal;
  VolSerial : dword;
begin
  GetVolumeInformation(PChar(Drive + ':\'), VolName, 255, @VolSerial,
      MaxCompLength, FileSysFlags, FileSysName, 255);
  if (not (VolName[0] in [#1, #0])) then
  begin result := string(VolName); exit; end;
  result := '';
end;

Получается следующее:
Если метка тома задана то все нормально, я ее получаю.
Но если ее нет - то я получаю, пустую строку.
А мне надо получить метки, так как они отображении в проводнике, как мне быть?
http://ipicture.ru/

Автор: Rrader 29.3.2009, 13:47
Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ShlObj, ShellAPI, ActiveX;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

function StrRetToStrW(pstr: PStrRet; const pidl: PItemIdList;
  out ppszName: PWideChar): HRESULT; stdcall; external 'shlwapi.dll';

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
const
  SHCONTF_STORAGE = $800;
var
  ID: PItemIDList;
  Malloc: IMalloc;
  Desktop: IShellFolder;
  MyComp: IShellFolder2;
  Enum: IEnumIDList;
  MCDrive: PItemIDList;
  FName: TStrRet;
  StringName: WideString;
  Buffer: PWideChar;
begin
  { Поправил }
  if Succeeded(CoGetMalloc(1, Malloc)) then
  try
    if Succeeded(SHGetSpecialFolderLocation(Handle, CSIDL_DRIVES, ID)) then
    try
      if Succeeded(SHGetDesktopFolder(Desktop)) then
      try
        if Succeeded(Desktop.BindToObject(ID, nil,
          IID_IShellFolder2, MyComp)) then
        try
          if Succeeded(MyComp.EnumObjects(Handle, SHCONTF_STORAGE, Enum)) then
          try
            while Enum.Next(1, MCDrive, PULONG(nil)^) = S_OK do
            try
              if Succeeded(MyComp.GetDisplayNameOf(MCDrive, SHGDN_NORMAL,
                FName)) then
              begin
                SetLength(StringName, MAX_PATH);
                if Succeeded(StrRetToStrW(@FName, MCDrive, Buffer)) then
                try
                  StringName := Buffer;
                finally
                  CoTaskMemFree(Buffer);
                end;
              end;
              ShowMessage(StringName);
            finally
              Malloc.Free(MCDrive);
            end;
          finally
            Enum := nil;
          end;
        finally
          MyComp := nil;
        end;
      finally
        Desktop := nil;
      end;
    finally
      Malloc.Free(ID);
    end;  
  finally
    Malloc := nil;
  end;
end;

end.

Автор: Router 29.3.2009, 14:49
А можно пояснить, что здесь происходит!

Автор: Rrader 29.3.2009, 15:44
Работа с моим компьютером средствами оболочки smile 

Автор: Alix 31.3.2009, 16:37
Если explorer.exe не запущен, все будет нормально?

Добавлено через 7 минут и 7 секунд
Вначале возникла идея воспользоваться National Language Support API, но сходу функция типа GetText(localeid, stringid) найдена не была. Да и скорее всего этот текст - в ресурсах explorer'a. Кстати, тоже вариант, даже если само приложение не запущено.

Добавлено через 8 минут и 51 секунду
Под текстом имею в виду строку "Локальный диск" и т.п.

Автор: Rrader 31.3.2009, 17:07
Цитата(Alix @  31.3.2009,  22:37 Найти цитируемый пост)
Если explorer.exe не запущен, все будет нормально?

Да

Автор: bems 31.3.2009, 18:42
Rrader, я в подобной задаче вместо вызова Malloc.Free делал CoTaskMemFree.
Про SHGetMalloc сказано 
Цитата
 This function is available through Microsoft Windows XP Service Pack 2 (SP2) and Windows Server 2003. It might be altered or unavailable in subsequent versions of Windows. Use the CoTaskMemFree and CoTaskMemAlloc functions in its place.


Еще для этой цели можно использовать ILFree, хотя и вместо нее говорят надо CoTaskMemFree
Цитата
Note  When using Microsoft Windows 2000 or later, use CoTaskMemFree rather than ILFree. ITEMIDLIST structures are always allocated with the Component Object Model (COM) task allocator on those platforms.


Короче что-то многовато тут способов. Почему ты делаешь именно так?

Автор: bems 31.3.2009, 19:22
Кстати с SHGetFileInfo с флажком SHGFI_DISPLAYNAME это будет короче

Автор: Rrader 1.4.2009, 13:05
Цитата(bems @  1.4.2009,  00:42 Найти цитируемый пост)
Про SHGetMalloc сказано

Цитата(bems @  1.4.2009,  00:42 Найти цитируемый пост)
Еще для этой цели можно использовать ILFree

Описание этих функций в разных редакциях MSDN было разным и двусмысленным. Сейчас, соглашусь, надо вносить исправления в коды. SHGetMalloc менять на CoGetMalloc. CoTaskMemXXX функции аналогичны методам интерфейса IMalloc, который для меня более удобен по возможностям, поэтому использую его.

Цитата(bems @  1.4.2009,  01:22 Найти цитируемый пост)
Кстати с SHGetFileInfo с флажком SHGFI_DISPLAYNAME это будет короче

Это реализовано через IShellFolder. Когда у нас на руках уже есть (как в этом примере) этот интерфейс, лучше использовать именно его smile

Автор: bems 1.4.2009, 19:14
Цитата(Rrader @  1.4.2009,  13:05 Найти цитируемый пост)
CoTaskMemXXX функции аналогичны методам интерфейса IMalloc, который для меня более удобен по возможностям, поэтому использую его
ну если бы только его, было бы понятно. Но в твоем примере есть и CoTaskMemFree. Может лучше однообразно? ну и явное присваивание nil интерфейсам имхо лишнее



Цитата(Rrader @  1.4.2009,  13:05 Найти цитируемый пост)
Это реализовано через IShellFolder. Когда у нас на руках уже есть (как в этом примере) этот интерфейс, лучше использовать именно его 
Дык в примере ты его сам получаешь, чтобы перечислить и узнать имена. Не феншуй.

Автор: Rrader 2.4.2009, 08:48
Цитата(bems @  2.4.2009,  01:14 Найти цитируемый пост)
Может лучше однообразно? 

Можно!
Цитата(bems @  2.4.2009,  01:14 Найти цитируемый пост)
ну и явное присваивание nil интерфейсам имхо лишнее

В связи с тем, что интерфейс является сложным автообъектом и тесно связан с COM, я всегда и везде самостоятельно дереференсирую ссылки. Для локального кода это забота Delphi, но ссылки могут быть и глобальными, на что новички и попадаются.
Цитата(bems @  2.4.2009,  01:14 Найти цитируемый пост)
Дык в примере ты его сам получаешь, чтобы перечислить и узнать имена. Не феншуй.

Не совсем понял. Я использую IShellFolder в примере и только его, все однообразно.

Автор: bems 2.4.2009, 17:47
Цитата(Rrader @  2.4.2009,  08:48 Найти цитируемый пост)
Не совсем понял. Я использую IShellFolder в примере и только его, все однообразно. 

ну ты выше говорил "Когда у нас на руках уже есть (как в этом примере) этот интерфейс, лучше использовать именно его "
А я в примере вижу, что "уже есть" на практике означает "я его получаю только чтобы добраться до имени". Я понимаю была бы "сопутствующая" задача, для которой нужен этот интерфейс, тогда можно заодгл им же воспользоваться и для получения имён. А тут только ради имен все это. 

Да  я в общем не против этого примера, я просто дусал вдруго есть какие-то высшие причины. По ходу похоже что ты просто так привык когда-то, и пишеш на автомате. Ну оно работает и ладно.

Автор: Rrader 2.4.2009, 18:05
Цитата(bems @  2.4.2009,  23:47 Найти цитируемый пост)
на практике означает "я его получаю только чтобы добраться до имени"

Я его получаю только исходя из удобства перечисления объектов. smile 

И мне нравится функционал IShellFolder(2), тем более, когда все рядом

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)