
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.118.139.238] |
![]() |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Всем привет
Разьясните пожалуйсто,как из файлов с расширением "*.msi" , с помощью API-функций из закладки "Сводка" извлечь информацию о Авторе и Теме Заранее благодарен. |
![]() |
Сообщ.
#2
,
|
|
Хм красивый вопрос... Первый раз такой слышу, никто раньше не интересовался.
По сабжу: MsiGetProductInfoFromScript Вообще смотри вот сюда: http://msdn.microsoft.com/library/en-us/msi/setup/installer_function_reference.asp |
Сообщ.
#3
,
|
|
|
Rouse_
кажется всё очень просто, может фаил что то и хранит внутри себя но все эти данные также есть в реестрее Как говоритсяб а ЛАРЧИК-то просто открывался !!!!! |
![]() |
Сообщ.
#4
,
|
|
Цитата ctranik @ но все эти данные также есть в реестрее Хм, я вообщето обьяснял про неустановленный MSI пакет ![]() |
![]() |
Сообщ.
#5
,
|
|
Вообще, *.msi - это обычные compound-файлы (или structured storage - файлы хранения структуированых данных) и они, помимо прочего, хранят в себе т.н. наборы cвойств, т.е. информацию о документе (которую видно на той же вкладке "Сводка"). Все эти св-ва можно прочитать напрямую из файла. Для этого в винде предназначены COM-интерфейсы IPropertySetStorage, IPropertyStorage, etc.
Вот небольшой примерчик считывания некоторых св-в из любых compound файлов, а так же св-ва обычных файлов (которые отображаются на вкладке "Сводка" диалогового окна "Свойства:"): ![]() ![]() 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 |
Сообщ.
#6
,
|
|
|
Krid, замечательный пример !
Меня смущает одно. Если эту прогу запустить дважды, то на второй раз она скажет "Error - файл уже используется". И это будет пока не перезагрузишься. ![]() Cдается мне что файлик то надо закрывать ... Так как здесь есть Open ![]() ![]() OleCheck(StgOpenStorage(StringToOleStr(OpenDialog1.FileName),nil, STGM_READ or STGM_SHARE_EXCLUSIVE,nil,0,stgRoot)); // открываем его , то должен быть и Close . Кстати, не подскажешь как его вызвать то ? |
Сообщ.
#7
,
|
|
|
Еще у меня вопрос... Я не понял что же дает 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. Обратите внимание на выделенно синим. Не это ли мешает открывать файл впоследствии? |
![]() |
|
|
Народ, ну, что серьезно никто не знает как решается проблема то ?
|
Сообщ.
#9
,
|
|
|
Krid, ну отзовись пожалуйста
![]() Цитата *.Экзе рэйсед экспепшен класс EOleSysError whith message "%1 уже существует" Чего это она ? |
![]() |
Сообщ.
#10
,
|
|
Цитата SexGenius @ Если эту прогу запустить дважды, то на второй раз она скажет "Error - файл уже используется". И это будет пока не перезагрузишься. Ну правильно, это из-за STGM_SHARE_EXCLUSIVE. Этот флаг задает монопольный доступ к файлу (или секции/хранилищу/набору св-в в нем) для одной программы. Просто, в то время как ты читаешь из файла, другая прога может в него писать (например поменять св-во). А это не есть гуд. Ну тут можно либо закрыть файл - т.е., после всех операций написать ![]() ![]() stgRoot:=nil; Цитата SexGenius @ При выборе pdf или вомг - файла прога пишет : Да это чего-то OleCheck мудрит. Я бы ее вообще убрал и написал что-то типа ![]() ![]() 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 (как-то она жисть осложняеть ![]() Вобщем, код подправил. Должно работать нормально. А так - эксперементируй и не ищи легких путей ![]() |
Сообщ.
#11
,
|
|
|
Цитата Krid, 05.10.2005, 19:32:12, 876404 Да это чего-то OleCheck мудрит. Я бы ее вообще убрал и написал что-то типа Тады при открытии djvu или pdf-файла прога пишет, как ты догадался, следующее: Цитата Can not open doc file |
![]() |
Сообщ.
#12
,
|
|
Дык, естественно! pdf - это не compound (doc/structured storage / хранилище структуированых данных). Они и не должны так открываться - у них совсем другой формат. Еще раз скажу, что таким макаром, как в примере могут открываться только compound файлы. А pdf и djvu к ним никакого отношения не имеют
![]() |
Сообщ.
#13
,
|
|
|
Цитата Krid, 05.10.2005, 20:44:11, 876474 Еще раз скажу, что таким макаром, как в примере могут открываться только compound файлы. А есть-ли какой-нить универсальный макар, которым можно считывать информацию со вкладки Сводка для любых файлов NTFS . Может какие-нить константы повтыкать другие в функции ? |
![]() |
Сообщ.
#14
,
|
|
Ах вон ты чего хочешь
![]() Дело в том, что NTFS позволяет для каждого файла создавать т.н. файловые потоки (files stream). По сути это те же файлы, только их не видно и они имеют "особые" атрибуты в ФС. С ними можно работать так же, как и с обычными файлами: создавать, удалять, записывать в них инфу (можно юзать почти все файловые API ф-ции). Когда ты открываешь вкладку "Свойства" и пишешь там чего-нить, винда создает для этого файла несколько потоков, в которые записывает то, что ты ввел. С потоками можно работать, например из ком. строки в консоли: ![]() ![]() Создание файла с потоком: 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. а можно и в программе (пример создания потока): ![]() ![]() 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, так и из обычных файлов (если, конечно у этих файлов есть набор св-в). |
Сообщ.
#15
,
|
|
|
Krid, огромадное спасибо !!! [+] !!!!
|