На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! user posted image
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.

Соблюдайте общие правила форума

Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как запустить программу/файл? (и дождаться ее завершения)
5. Как перехватить API-функции, поставить hook? (перехват сообщений от мыши, клавиатуры - внедрение в удаленное адресное прстранство)
... (продолжение следует) ...

Внимание:
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки - бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Rouse_, user posted image Krid

Модераторы: Rouse_, Krid
  
> Как извлечь информацию из файла , как на вкладке "Сводка" в Windows Explorer
    Всем привет

    Разьясните пожалуйсто,как из файлов с расширением "*.msi" , с помощью API-функций
    из закладки "Сводка" извлечь информацию о Авторе и Теме

    Заранее благодарен.
      Хм красивый вопрос... Первый раз такой слышу, никто раньше не интересовался.
      По сабжу: MsiGetProductInfoFromScript

      Вообще смотри вот сюда: http://msdn.microsoft.com/library/en-us/msi/setup/installer_function_reference.asp
        Rouse_

        кажется всё очень просто, может фаил что то и хранит внутри себя
        но все эти данные также есть в реестрее

        Как говоритсяб а ЛАРЧИК-то просто открывался !!!!!
          Цитата ctranik @
          но все эти данные также есть в реестрее

          Хм, я вообщето обьяснял про неустановленный MSI пакет :)
            Вообще, *.msi - это обычные compound-файлы (или structured storage - файлы хранения структуированых данных) и они, помимо прочего, хранят в себе т.н. наборы cвойств, т.е. информацию о документе (которую видно на той же вкладке "Сводка"). Все эти св-ва можно прочитать напрямую из файла. Для этого в винде предназначены COM-интерфейсы IPropertySetStorage, IPropertyStorage, etc.
            Вот небольшой примерчик считывания некоторых св-в из любых compound файлов, а так же св-ва обычных файлов (которые отображаются на вкладке "Сводка" диалогового окна "Свойства:"):
            ExpandedWrap disabled
              unit Unit1;
               
              interface
               
              uses
                Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
                Dialogs, StdCtrls, ComCtrls;
               
              type
                TForm1 = class(TForm)
                  Button1: TButton;
                  ListView1: TListView;
                  OpenDialog1: TOpenDialog;
                  procedure Button1Click(Sender: TObject);
                  procedure FormCreate(Sender: TObject);
                private
                  { Private declarations }
                public
                  { Public declarations }
                end;
               
              var
                Form1: TForm1;
               
              implementation
               
              {$R *.dfm}
               
              uses ActiveX, ComObj;
               
              function StgOpenStorageEx(const pwcsName : POleStr; grfMode : LongInt; stgfmt : DWORD;
                                         grfAttrs : DWORD;  pStgOptions : Pointer; reserved2 : Pointer;
                                          riid : PGUID; out stgOpen : IStorage ) : HResult; stdcall; external 'ole32.dll';
               
               
              const
              // GUID для набора св-в SummaryInformation
               FMTID_SummaryInformation  : TGUID = '{F29F85E0-4FF9-1068-AB91-08002B27B3D9}';
               IID_IPropertySetStorage   : TGUID = '{0000013A-0000-0000-C000-000000000046}';
               
                STGFMT_FILE = 3;
                STGFMT_ANY = 4;
               
              type
               PPropSpecArray=^TPropSpecArray;  // массив спецификаций св-в
               TPropSpecArray=array[0..999] of TPropSpec;
               
               PPropVariantArray=^TPropVariantArray; // массив - приемник, куда будут помещены значения нужных св-в
               TPropVariantArray=array[0..999] of TPropVariant;
               
              // Этот код в стиле VB чисто для примера. Узнать, какая FS в системе можно и через WinAPI
              function IsNTFS(AFileName : string) : boolean;
              var
               fso, drv : OleVariant;
              begin
              fso := CreateOleObject('Scripting.FileSystemObject');
              drv := fso.GetDrive(fso.GetDriveName(AFileName));
              Result:=drv.FileSystem = 'NTFS'
              end;
               
              procedure TForm1.Button1Click(Sender: TObject);
              var
               stgRoot:IStorage;
               stgPS:IPropertySetStorage;
               stgP:IPropertyStorage;
               ps:PPropSpecArray;
               pv:PPropVariantArray;
               lit:TListItem;  // значения св-в записываем в ListView
              begin
               
               if (not OpenDialog1.Execute) then exit;  // выбираем файл
               
               // Проверяем: если это не compound file и система - не NTFS, тогда выходим.
               // (для compound файлов FS не важна)
               if (StgIsStorageFile(StringToOleStr(OpenDialog1.FileName))<>S_OK) then
                 if (not IsNTFS(OpenDialog1.FileName)) then
                begin
                 MessageBox(Handle,'NTFS needed for non-compound files','Error',MB_ICONERROR);
                 exit;
                end;
               
               
               ListView1.Clear;
               
                if (StgOpenStorageEx(StringToOleStr(OpenDialog1.FileName), STGM_READ or STGM_SHARE_DENY_WRITE,
                                      STGFMT_ANY, 0, nil,  nil,
                                     @IID_IPropertySetStorage, stgRoot)<>S_OK) then  // открываем его
                begin
                 MessageBox(Handle,'Can not open file','Error',MB_ICONERROR);
                 exit;
                end;
               
               stgPS:=stgRoot as IPropertySetStorage;  // ссылаемся на нужный интерфейс
               if (stgPS.Open(FMTID_SummaryInformation,STGM_READ or STGM_SHARE_EXCLUSIVE,stgP)<>S_OK) then // открываем набор св-в
               begin
                MessageBox(Handle,'Can not open property set','Error',MB_ICONERROR);
                exit;
               end;
               
               ps:=nil;
               pv:=nil;
               try
                 GetMem(ps,SizeOf(TPropSpec));
                 GetMem(pv,SizeOf(TPropVariant));
               
                 ps[0].ulKind:=PRSPEC_PROPID;   // считываем св-ва по их идентификатору (см. ActiveX.pas)
               
              //  Прочитаем для примера несколько св-в.
              //  Для наглядности читаем по одному св-ву из потока (можно за один раз прочитать и больше),
              //  поэтому каждый раз значение будет лежать в pv[0].
              //  В данном случае читаем только строковые св-ва.
               
                 ps[0].propid:=PIDSI_TITLE;     // заголовок
                 lit:=ListView1.Items.Add;
                 lit.Caption:='Title';
                 if (stgP.ReadMultiple(1, @ps[0], @pv[0])=S_OK) then  // читаем св-во
                 lit.SubItems.Add(pv[0].pszVal) // добавляем в ListView
                 else lit.SubItems.Add('');
               
                 ps[0].propid:=PIDSI_SUBJECT;   // тема
                 lit:=ListView1.Items.Add;
                 lit.Caption:='Subject';
                 if (stgP.ReadMultiple(1, @ps[0], @pv[0])=S_OK) then
                 lit.SubItems.Add(pv[0].pszVal)
                 else lit.SubItems.Add('');
               
                 ps[0].propid:=PIDSI_AUTHOR;   // автор
                 lit:=ListView1.Items.Add;
                 lit.Caption:='Author';
                 if (stgP.ReadMultiple(1, @ps[0], @pv[0])=S_OK) then
                 lit.SubItems.Add(pv[0].pszVal)
                 else lit.SubItems.Add('');
               
                 ps[0].propid:=PIDSI_COMMENTS; // комментарий
                 lit:=ListView1.Items.Add;
                 lit.Caption:='Comment';
                 if (stgP.ReadMultiple(1, @ps[0], @pv[0])=S_OK) then
                 lit.SubItems.Add(pv[0].pszVal)
                 else lit.SubItems.Add('');
               
                 ps[0].propid:=PIDSI_REVNUMBER; // номер редакции
                 lit:=ListView1.Items.Add;
                 lit.Caption:='Revision';
                 if (stgP.ReadMultiple(1, @ps[0], @pv[0])=S_OK) then
                 lit.SubItems.Add(pv[0].pszVal)
                 else lit.SubItems.Add('');
               
                 ps[0].propid:=PIDSI_APPNAME;   // приложение, создавшее пакет
                 lit:=ListView1.Items.Add;
                 lit.Caption:='Application';
                 if (stgP.ReadMultiple(1, @ps[0], @pv[0])=S_OK) then
                 lit.SubItems.Add(pv[0].pszVal)
                 else lit.SubItems.Add('');
               
               finally
                 if assigned(ps) then FreeMem(ps);
                 if assigned(pv) then FreeMem(pv);
                 stgP:=nil;
                 stgPS:=nil;
                 stgRoot:=nil;
               end;
              end;
               
              procedure TForm1.FormCreate(Sender: TObject);
              begin
               // наборы св-в могут храниться не только в *.msi, но и в любых compound-файлах (например в документах MS Office)
               OpenDialog1.Filter:='MSI Databases (*.msi)|*.msi|MS Office Documents (*.doc;*.xls)|*.doc; *.xls|All Files (*.*)|*.*'
              end;
               
              end.


            В наборе SummaryInformation есть еще несколько св-в (не все из них строковые). Также compound-файлы могут содержать и другие наборы св-в, например DocumentSummaryInformation, UserDefinedProperties, а также какие-нибудь произвольно определенные пользователем. Вся инфа - в MSDN. Прототипы, константы, структуры - в ActiveX.pas
              Krid, замечательный пример !
              Меня смущает одно. Если эту прогу запустить дважды, то на второй раз она скажет "Error - файл уже используется". И это будет пока не перезагрузишься. :huh:
              Cдается мне что файлик то надо закрывать ... Так как здесь есть Open
              ExpandedWrap disabled
                OleCheck(StgOpenStorage(StringToOleStr(OpenDialog1.FileName),nil,
                                         STGM_READ or STGM_SHARE_EXCLUSIVE,nil,0,stgRoot));   // открываем его

              , то должен быть и Close .
              Кстати, не подскажешь как его вызвать то ?
                Еще у меня вопрос... Я не понял что же дает STGM_SHARE_EXCLUSIVE ?
                В MSDN написано

                Цитата
                STGM_SHARE_EXCLUSIVE
                Prevents others from subsequently opening the object in any mode. Note that this value is not a simple bitwise OR operation of the STGM_SHARE_DENY_READ and STGM_SHARE_DENY_WRITE values. In transacted mode, sharing of STGM_SHARE_DENY_WRITE or STGM_SHARE_EXCLUSIVE can significantly improve performance since they don't require snapshotting. See the following Remarks section for more information about transactioning.

                Обратите внимание на выделенно синим. Не это ли мешает открывать файл впоследствии?
                  Народ, ну, что серьезно никто не знает как решается проблема то ?
                    Krid, ну отзовись пожалуйста :( . При выборе pdf или вомг - файла прога пишет :

                    Цитата
                    *.Экзе рэйсед экспепшен класс EOleSysError whith message "%1 уже существует"


                    Чего это она ?
                      Цитата SexGenius @
                      Если эту прогу запустить дважды, то на второй раз она скажет "Error - файл уже используется". И это будет пока не перезагрузишься.

                      Ну правильно, это из-за STGM_SHARE_EXCLUSIVE. Этот флаг задает монопольный доступ к файлу (или секции/хранилищу/набору св-в в нем) для одной программы. Просто, в то время как ты читаешь из файла, другая прога может в него писать (например поменять св-во). А это не есть гуд.

                      Ну тут можно либо закрыть файл - т.е., после всех операций написать
                      ExpandedWrap disabled
                         stgRoot:=nil;
                      либо открыть, например так STGM_READ or STGM_SHARE_DENY_WRITE (вообще, поэксперементируй с флагами - их там до е@#-матери, см. MSDN). А вообще, по-идее, в моем примере такой ошибки быть не должно - файл закрывается по выходе из Button1Click (stgRoot - локальная).

                      Цитата SexGenius @
                      При выборе pdf или вомг - файла прога пишет :

                      Да это чего-то OleCheck мудрит. Я бы ее вообще убрал и написал что-то типа
                      ExpandedWrap disabled
                        if (StgOpenStorage(StringToOleStr(OpenDialog1.FileName),nil,
                                           STGM_READ or STGM_SHARE_EXCLUSIVE,nil,0,stgRoot)<>S_OK) then
                          begin
                           MessageBox(Handle,'Can not open doc file','Error',MB_ICONERROR);
                           exit;
                          end;

                      И кстати, везде убрал бы эту OleCheck (как-то она жисть осложняеть :)) и все бы делал ручками.

                      Вобщем, код подправил. Должно работать нормально. А так - эксперементируй и не ищи легких путей :)
                        Цитата Krid, 05.10.2005, 19:32:12, 876404
                        Да это чего-то OleCheck мудрит. Я бы ее вообще убрал и написал что-то типа

                        Тады при открытии djvu или pdf-файла прога пишет, как ты догадался, следующее:
                        Цитата
                        Can not open doc file
                          Дык, естественно! pdf - это не compound (doc/structured storage / хранилище структуированых данных). Они и не должны так открываться - у них совсем другой формат. Еще раз скажу, что таким макаром, как в примере могут открываться только compound файлы. А pdf и djvu к ним никакого отношения не имеют :no:
                            Цитата Krid, 05.10.2005, 20:44:11, 876474
                            Еще раз скажу, что таким макаром, как в примере могут открываться только compound файлы.

                            А есть-ли какой-нить универсальный макар, которым можно считывать информацию со вкладки Сводка для любых файлов NTFS . Может какие-нить константы повтыкать другие в функции ?
                              Ах вон ты чего хочешь :) Ну это тоже можно сделать.
                              Дело в том, что NTFS позволяет для каждого файла создавать т.н. файловые потоки (files stream). По сути это те же файлы, только их не видно и они имеют "особые" атрибуты в ФС. С ними можно работать так же, как и с обычными файлами: создавать, удалять, записывать в них инфу (можно юзать почти все файловые API ф-ции).
                              Когда ты открываешь вкладку "Свойства" и пишешь там чего-нить, винда создает для этого файла несколько потоков, в которые записывает то, что ты ввел.
                              С потоками можно работать, например из ком. строки в консоли:
                              ExpandedWrap disabled
                                Создание файла с потоком:
                                type nul > somefile.txt:Stream
                                 
                                Запись в поток:
                                echo "Something" >> somefile.txt:Stream
                                 
                                Чтение из потока:
                                more < somefile:Stream
                                 
                                Копирование содержимого существующего файла в поток:
                                type file1.txt >> somefile.txt:Stream
                                 
                                Копирование содержимого потока в файл:
                                more < somefile.txt:Stream >> file2.txt
                                 
                                Удаление потоков выполняется через DeleteFile.

                              а можно и в программе (пример создания потока):
                              ExpandedWrap disabled
                                procedure TForm1.Button1Click(Sender: TObject);
                                var
                                 dwRet:DWORD;
                                 hFile,hStream:THandle;
                                begin
                                // создаем файл
                                hFile:=CreateFile( 'C:\testfile.txt', GENERIC_WRITE, FILE_SHARE_WRITE, nil, OPEN_ALWAYS, 0, 0);
                                CloseHandle(hFile);
                                 
                                // создаем в нем поток и пишем в него чего-нибудь.
                                hStream:=CreateFile( 'C:\testfile.txt:mystream', GENERIC_WRITE, FILE_SHARE_WRITE, nil, OPEN_ALWAYS, 0, 0);
                                WriteFile( hStream, 'This is a stream', 17, dwRet, nil );
                                CloseHandle(hStream);
                                end;

                              Соотв. читается инфа из потока ф-цией ReadFile.
                              Т.е., по идее, нужно открыть один из потоков, созданных виндой при записи св-в, прочитать его и выудить оттуда нужную инфу.

                              Но в Win2K появилась ф-ция StgOpenStorageEx, которая сама всем этим занимается. Причем в ней можно задать флаги так, что она будет одинаково работать и с compound файлами (содержащими св-ва внутри себя) и с обычными файлами, св-ва которых находятся в отдельном потоке - винда сама определит, что за файл.

                              Короче пример в посте #5 я изменил - теперь он может читать св-ва как из compound, так и из обычных файлов (если, конечно у этих файлов есть набор св-в).
                                Krid, огромадное спасибо !!! [+] !!!!
                                  Господа программисты, помогите!
                                  Имею биологическое образование. Третью неделю лажу по интернету, одно понял - без вашей помощи мне не обойтись.
                                  Мне нужно получать свойства (автор, ключевые слова) из не compound файлов (в частности TIFF, JPEG). Как я понял, на этом форуме говорится именно об этом. Но разговор окончился на том, что Krid изменил код на подходящий, и... все.
                                  Выручайте! Опубликуйте исходник.
                                    Цитата к.б.н. @
                                    Мне нужно получать свойства (автор, ключевые слова) из не compound файлов (в частности TIFF, JPEG).


                                    Вот тебе пример. Снимает то, что тебе нужно и немного еще (из дополнительных свойств нет времени писать демку полного разбора)

                                    ExpandedWrap disabled
                                      uses
                                        GDIPOBJ,
                                        GDIPAPI,
                                        GDIPUTIL,
                                        ActiveX;
                                       
                                      {$R *.dfm}
                                       
                                      procedure TForm1.Button1Click(Sender: TObject);
                                       
                                        function GetAdvTagData(const ID: Integer): String;
                                        const
                                          TAG_Title     = 40091;
                                          TAG_Comments  = 40092;
                                          TAG_Author    = 40093;
                                          TAG_KeyWords  = 40094;
                                          TAG_Subject   = 40095;
                                        begin
                                          case ID of
                                            TAG_Title:    Result := 'Title';
                                            TAG_Comments: Result := 'Comments';
                                            TAG_Author:   Result := 'Author';
                                            TAG_KeyWords: Result := 'KeyWords';
                                            TAG_Subject:  Result := 'Subject';
                                          else
                                            Result := '';
                                          end;
                                        end;
                                       
                                      var
                                        GDIImage: TGPImage;
                                        I, ACount, PropSize: Integer;
                                        PropertyesList: array of TPropId;
                                        PropertyItem: PPropertyItem;
                                        PropName: String;
                                        PropValue: WideString;
                                        ByteValue: DWORD;
                                      begin
                                        if OpenDialog1.Execute then
                                        begin
                                          Memo1.Clear;
                                          GDIImage := TGPImage.Create(OpenDialog1.FileName);
                                          try
                                            ACount := GDIImage.GetPropertyCount;
                                            SetLength(PropertyesList, ACount);
                                            GDIImage.GetPropertyIdList(ACount, @PropertyesList[0]);
                                            for I := 0 to ACount - 1 do
                                            begin
                                              PropSize := GDIImage.GetPropertyItemSize(PropertyesList[I]);
                                              GetMem(PropertyItem, PropSize);
                                              try
                                                GDIImage.GetPropertyItem(PropertyesList[I], PropSize, PropertyItem);
                                                PropName := GetAdvTagData(PropertyesList[I]);
                                                if PropName <> '' then
                                                begin
                                                  SetLength(PropValue, PropertyItem^.length);
                                                  Move(PropertyItem^.value^, PropValue[1], PropertyItem^.length);
                                                end
                                                else
                                                begin
                                                  PropName := GetMetaDataIDString(PropertyItem^.id);
                                                  ByteValue := 0;
                                                  if PropertyItem^.type_ in
                                                    [PropertyTagTypeByte, PropertyTagTypeShort,
                                                     PropertyTagTypeLong] then
                                                  begin
                                                    if PropertyItem^.length <= 4 then
                                                    begin
                                                      Move(PropertyItem^.value^, ByteValue, PropertyItem^.length);
                                                      PropValue := IntToStr(ByteValue);
                                                    end
                                                    else
                                                    begin
                                                      SetLength(PropValue, PropertyItem^.length);
                                                      Move(PropertyItem^.value^, PropValue[1], PropertyItem^.length);
                                                    end;
                                                  end;
                                                end;
                                                Memo1.Lines.Add(PropName + ' - ' + PropValue);
                                              finally
                                                FreeMem(PropertyItem);
                                              end;
                                            end;
                                          finally
                                            GDIImage.Free;
                                          end;
                                        end;
                                      end;
                                      Цитата к.б.н. @
                                      Мне нужно получать свойства (автор, ключевые слова) из не compound файлов (в частности TIFF, JPEG). Как я понял, на этом форуме говорится именно об этом.

                                      Не правильно понял. Читай внимательно предыдущие посты и введение к коду из фака (как извлечь "Сводку" свойств файла). Там говорится о стандартных св-вах, хранящихся либо внутри compound файлов либо в файловых потоках, ассоциированных с файлом.
                                      А получение специфических св-в файлов определённого типа - это совсем из другой оперы. Тут используются свои наборы API (см. например, код Rouse_ - там юзаются ф-ции из gdiplus.dll)/свои интерфейсы/прямое чтение "тэгов" из файла/etc.
                                      Вобщем, твой вопрос (о св-вах TIFF, JPEG) скорее для форума Delphi: Multimedia
                                        Благодарю!
                                        Отличный код. Все работает. Правда, чтобы получить только необходимое (название, коммент., автор...), я его несколько укоротил.

                                        Для таких же тупых как я, прокомментирую:
                                        Здесь используется новый интерфейс GDI+. Работает на Windows XP и .NET Server, на более ранних ПО не работает (без определенной доработки).
                                        Чтобы с этим кодом заработал Delphi, в него надо установить соответствующие заголовочные файлы (подробности http://www.delphikingdom.com/asp/viewitem.asp?catalogid=772 )
                                          MSI файлы - это наборы таблиц и комманд для интерпретатора msiexec. Разумеется вы можете опросить таблицы внутри msi на предмет количесва названия файлов всего что вы пожелаете, есть даже SQL подобный язык. Для интересующихся - скачайте Microsoft MSI Orca. (http://www.technipages.com/downloadview-details-44-Orca_MSI_Editor.html).

                                          Примерно код для прочтения какого либо свойтсва из MSI:
                                          ExpandedWrap disabled
                                            const msilib = 'msi.dll';
                                             
                                            type
                                             
                                              MSIHANDLE = DWORD;    
                                              TMsiHandle = MSIHANDLE;
                                             
                                            function MsiCloseHandle(hAny: MSIHANDLE):UINT;stdcall;external msilib name 'MsiCloseHandle';
                                            function MsiOpenProduct(szProduct:LPCSTR;var hProduct:MSIHANDLE):UINT;stdcall;external msilib name 'MsiOpenProductA';
                                            function MsiGetProductProperty(hProduct:MSIHANDLE;szProperty:LPCSTR;lpValueBuf:LPSTR;pcchValueBuf:LPDWORD):UINT;stdcall; external msilib name 'MsiGetProductPropertyA';
                                            function MsiSetInternalUI(dwUILevel:INSTALLUILEVEL;phWnd:LPHWND):INSTALLUILEVEL;stdcall; external msilib name 'MsiSetInternalUI';
                                             
                                            function GetMSIProperty(aProductCode:string):string;
                                            var
                                             msi:TMSIHandle;
                                             t:string;
                                             
                                             function _getmsiproperty(_name:string):string;
                                             var
                                              txt:PChar;
                                              sz:DWORD;
                                             begin
                                              sz:=MAX_PATH;
                                              txt:=AllocMem(sz+1);
                                              if MsiGetProductProperty(msi,PChar(_name),txt,@sz)=ERROR_MORE_DATA then
                                               begin
                                                ReAllocMem(txt,sz+1);
                                                MsiGetProductProperty(msi,PChar(_name),txt,@sz);
                                               end;
                                              SetString(Result,txt,sz);
                                              FreeMem(txt,sz+1);
                                             end;
                                             
                                            begin
                                             MsiSetInternalUI(2,nil); // скрываем GUI
                                             if MsiOpenProduct(PChar(aProductCode),msi)=ERROR_SUCCESS then
                                              begin
                                               t:=_getmsiproperty('ARPPRODUCTICON'); // главная иконка приложения
                                                   if t='' then t:=_getmsiproperty('ProductIcon');
                                                   if t='' then t:=_getmsiproperty('CompleteSetupIcon');
                                                   if t='' then t:=_getmsiproperty('CustomSetupIcon');
                                                   if t='' then t:=_getmsiproperty('InfoIcon');
                                                   if t='' then t:=_getmsiproperty('InstallerIcon');
                                                   if t='' then t:=_getmsiproperty('RemoveIcon');
                                                   if t='' then t:=_getmsiproperty('RepairIcon');
                                                   Result:=t;
                                                   MsiCloseHandle(msi);
                                              end;
                                            end;
                                          Сообщение отредактировано: Krid -
                                            работаю на builder c++,

                                            но к сожалению, у меня при вызове
                                            hr = pPropSetStg->Open(PropSetfmtid, STGM_READ, &pPropStg );
                                            получаю hr равную -2147286785, т.е. возникает ошибка, для doc файлов такая ошибка не возникает

                                            вот весь участок кода:
                                            ExpandedWrap disabled
                                              FMTID PropSetfmtid={0xf29f85e0,0x4ff9,0x1068,{0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9 }};
                                              HRESULT hr = S_OK;
                                              IPropertyStorage *pPropStg = NULL;
                                              IPropertySetStorage *pPropSetStg = NULL;
                                              IStorage *stgRoot = NULL;
                                              PROPSPEC propspec;
                                              PROPVARIANT propRead;
                                               
                                              if (StgOpenStorageEx(StringToOleStr(FileName), STGM_READ | STGM_SHARE_DENY_WRITE,
                                              STGFMT_ANY, 0, NULL, NULL, IID_IPropertySetStorage, reinterpret_cast<void**>(&pPropSetStg))
                                              != S_OK) return;
                                               
                                              //if (pPropSetStg->Open(PropSetfmtid, STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_READ, &pPropStg ) != S_OK)
                                              // return;
                                              hr = pPropSetStg->Open(PropSetfmtid, STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_READ, &pPropStg );
                                               
                                              propspec.ulKind = PRSPEC_PROPID;
                                              propspec.propid = 0x00000002;
                                               
                                              pPropStg->ReadMultiple(1, &propspec, &propRead);
                                              AnsiString Title = propRead.pszVal;

                                            подскажите пожалуйста как можно считать свойства из pdf и djvu файла? почему возникает ошибка?
                                              Доброго времени суток.
                                              Подскажите пожалуйста.
                                              Использую за основу код из сообщения #5 от Krid.
                                              Но я хочу получить пользовательское свойство из .DOC файла.
                                              Вот такой код получился.

                                              ExpandedWrap disabled
                                                procedure TForm1.Button1Click(Sender: TObject);
                                                var
                                                  stgRoot: IStorage;
                                                  stgPS: IPropertySetStorage;
                                                  stgP: IPropertyStorage;
                                                  ps: ^TPropSpec;
                                                  pv: ^TPropVariant;
                                                  ReturnCode: Integer;
                                                begin
                                                // выбираем файл
                                                  if (not OpenDialog1.Execute) then
                                                    exit;
                                                 
                                                  // Проверяем: если это не compound file и система - не NTFS, тогда выходим.
                                                  // (для compound файлов FS не важна)
                                                  if (StgIsStorageFile(StringToOleStr(OpenDialog1.FileName))<>S_OK) then
                                                    if (not IsNTFS(OpenDialog1.FileName)) then begin
                                                      MessageBox(Handle,'NTFS needed for non-compound files','Error',MB_ICONERROR);
                                                      exit;
                                                    end;
                                                 
                                                  if (StgOpenStorageEx(StringToOleStr(OpenDialog1.FileName), STGM_READ or STGM_SHARE_DENY_WRITE,
                                                                        STGFMT_ANY, 0, nil,  nil,
                                                                       @IID_IPropertySetStorage, stgRoot)<>S_OK) then  // открываем его
                                                  begin
                                                    MessageBox(Handle,'Can not open file','Error',MB_ICONERROR);
                                                    exit;
                                                  end;
                                                 
                                                  stgPS := stgRoot as IPropertySetStorage;  // ссылаемся на нужный интерфейс
                                                  if (stgPS.Open(FMTID_SummaryInformation, STGM_READ or STGM_SHARE_EXCLUSIVE, stgP) <> S_OK) then // открываем набор св-в
                                                  begin
                                                    MessageBox(Handle,'Can not open property set','Error',MB_ICONERROR);
                                                    exit;
                                                  end;
                                                  ps:=nil;
                                                  pv:=nil;
                                                  try
                                                    GetMem(ps,SizeOf(TPropSpec));
                                                    GetMem(pv,SizeOf(TPropVariant));
                                                 
                                                    // свойство по номеру
                                                //    ps.ulKind := PRSPEC_PROPID;
                                                //    ps.propid := PIDSI_TITLE;
                                                 
                                                    // свойство по имени
                                                    ps.ulKind := PRSPEC_LPWSTR;
                                                    ps.lpwstr := 'QWERTY';
                                                 
                                                    // читаем св-во
                                                    ReturnCode := stgP.ReadMultiple(1, ps, pv);
                                                    if ReturnCode = S_OK then
                                                      ShowMessage(pv.pszVal)
                                                    else
                                                      ShowMessage('Error!!!');
                                                  finally
                                                    if assigned(ps) then
                                                      FreeMem(ps);
                                                    if assigned(pv) then
                                                      FreeMem(pv);
                                                    stgP := nil;
                                                    stgPS := nil;
                                                    stgRoot := nil;
                                                  end;
                                                 
                                                end;

                                              В тестируемом DOC файле создал свойство QWERTY при чтении свойство по имени всегда S_FALSE.
                                              Чтение стандартных свойств по номеру работает.
                                              Подскажите, пожалуйста что я не правильно делаю.
                                                Пользовательские св-ва надо считывать из набора UserDefinedProperties, а ты открываешь SummaryInformation.

                                                В stgPS.Open вместо FMTID_SummaryInformation юзай FMTID_UserDefinedProperties ({D5CDD505-2E9C-101B-9397-08002B2CF9AE})
                                                  Спасибо большое. Получилось.
                                                  1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                                  0 пользователей:


                                                  Рейтинг@Mail.ru
                                                  [ Script execution time: 0,0664 ]   [ 15 queries used ]   [ Generated: 18.07.25, 06:02 GMT ]