Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Диалог свойств файла (ShellExecuteEx)


R1 ©   (2004-08-18 17:38:00) 

Написал элементарную программку для показа диалога свойств файла, переданного в командной строке:

program showprop;

uses
 ShellApi;

var
 ShellExecuteInfo: TShellExecuteInfo;
begin
 if ParamCount <> 1 then
   WriteLn('One and only parameter expected.')
 else
 begin
   FillChar(ShellExecuteInfo, SizeOf(ShellExecuteInfo), 0);
   ShellExecuteInfo.cbSize := SizeOf(ShellExecuteInfo);
   ShellExecuteInfo.lpFile := PChar(ParamStr(1));
   ShellExecuteInfo.lpVerb := 'properties';
   ShellExecuteInfo.fMask := SEE_MASK_INVOKEIDLIST;
   ShellExecuteEx(@ShellExecuteInfo);
 end;
end.

Однако при запуске:
showprop.exe c:\autoexec.bat
результатов работы программки (диалога свойств файла autoexec.bat) не наблюдается.

После небольшой добавки, а именно вставки вызова MessageBox сразу после ShellExecuteEx(@ShellExecuteInfo):

program showprop;

uses
 ShellApi, Windows;

var
 ShellExecuteInfo: TShellExecuteInfo;
begin
 if ParamCount <> 1 then
   WriteLn('One and only parameter expected.')
 else
 begin
   FillChar(ShellExecuteInfo, SizeOf(ShellExecuteInfo), 0);
   ShellExecuteInfo.cbSize := SizeOf(ShellExecuteInfo);
   ShellExecuteInfo.lpFile := PChar(ParamStr(1));
   ShellExecuteInfo.lpVerb := 'properties';
   ShellExecuteInfo.fMask := SEE_MASK_INVOKEIDLIST;
   ShellExecuteEx(@ShellExecuteInfo);
   MessageBox(0, 'qwerty', 'qwerty', MB_OK);
 end;
end.

желаемое окно свойств файла появляется, причем через некоторое время после (!) MessageBox'а. А после нажатия на ОК MessageBox'а окно свойств исчезает.

Что и как надо делать, чтобы вывести окно свойств файла (и только его) и чтобы оно не исчезало самопроизвольно, а только когда я сам его закрою?


R1   (2004-08-20 20:01:00) [1]

1) У меня вообще explorer.exe отсутствует в диспетчере задач. У меня Aston. :) Но мысль понятна, все верно. Да, действительно, при снятии explorer.exe, все открытые в нем окна свойств закрываются. Так как же он их так запускает?

2) Возникает другой вопрос - а как узнать количество потоков, запущеных процессом?

Можно, конечно, узнать количество дескрипторов - GetProcessHandleCount - и на этом как-то основываться, но, может быть, я чего-то в хелпе не заметил и можно легко узнать количество потоков?

И потом... Мне кажется, это тоже не выход. Сейчас попытаюсь объяснить...

Очередной вариант:

program showprop;

uses
 ShellApi, Windows, SysUtils;

function WaitingThreadFunc(PropCaption: PChar): DWORD; stdcall;
begin
 while FindWindow('#32770 (Dialog)', PropCaption) 0 do
   ;
 Result := 0;
end;

var
 ShellExecuteInfo: TShellExecuteInfo;
 ThreadHandle: THandle;
 szCaption: PChar;
 ThreadID: DWORD;
 S: string;
begin
 if ParamCount = 1 then
 begin
   FillChar(ShellExecuteInfo, SizeOf(ShellExecuteInfo), 0);
   ShellExecuteInfo.cbSize := SizeOf(ShellExecuteInfo);
   ShellExecuteInfo.lpFile := PChar(ParamStr(1));
   ShellExecuteInfo.lpVerb := 'properties';
   ShellExecuteInfo.fMask := SEE_MASK_INVOKEIDLIST;
   ShellExecuteEx(@ShellExecuteInfo);

   GetMem(szCaption, 80);
   S := 'Ñâîéñòâà: ' + ParamStr(1);
   StrCopy(szCaption, PChar(S));
   ThreadHandle := CreateThread(nil, 0, @WaitingThreadFunc,
     szCaption, 0 {CREATE_SUSPENDED}, ThreadID);
   //SetThreadPriority(ThreadHandle, THREAD_PRIORITY_IDLE);
   //ResumeThread(ThreadHandle);
   WaitForSingleObject(ThreadHandle, INFINITE);
   CloseHandle(ThreadHandle);
   FreeMem(szCaption);
 end;
end.

не проканал, т.к. на момент, когда поток (WaitingThreadFunc) получает управление, окно свойств еще не создано, и он честным образом тут же возвращает ноль - приложение закрывается, окна свойств я так и не увидел. (Если в потоке вместо FindWindow поставить MessageBox, то сначала появляется он, а уж после него - окно свойств файла.) Мне кажется, что вариант с подсчетом количества потоков отработает по той же схеме. Ну не создасться окно свойств, пока прога хоть чем-то занимается...

Все ж таки, всемогущий ALL - как показать окно свойств и чтоб оно не исчезло, пока его не закроют?

Может быть, запускать процесс explorer.exe с какими-нибудь параметрами?


nikkie   (2004-08-20 17:36:00) [2]

>Ведь если в проводнике вызвать "Свойства", потом закрыть проводник - диалог-то остается...
это ты не проводник закрываешь, а одно из его окошек.
попробуй explorer.exe через TaskManager снять.

Вопрос остается открытым
>банально считать количество потоков при завершении программы и не выходить, пока их больше, чем 1.


R1   (2004-08-20 17:02:00) [3]

Понятно. Овчинка, действительно, выделки не стоит.

Вопрос остается открытым: таки как показать диалог свойств файла, закрыться, а диалог чтобы остался? Ведь если в проводнике вызвать "Свойства", потом закрыть проводник - диалог-то остается...


nikkie   (2004-08-19 15:39:00) [4]

поищи по этому форуму - обсуждается периодически внедрение в чужой процесс. обычно к Рихтеру отсылают. я все варианты не скажу, только что вспоминается: AppInitDLL, глобальный хук, CreateRemoteThread на NT-системах. но городить это ради того, чтобы диалог не закрывался - овчинка выделки не стоит. другое дело, если твое приложение можно реализовать как shell extension dll, например. тогда уже автоматически в процессе explorer-a окажешься.


R1   (2004-08-19 15:20:00) [5]

nikkie ©   (19.08.04 02:30) [5]

> прицепиться к чужому процессу (идеально explorer.exe - и вызвать ShellExecute в его контексте)

Прошу прощения за возможную наивность, но как это сделать - вызвать ShellExecuteEx в контексте другого процесса, в частности, explorer.exe?

Очередной вариант:

program showprop;

uses
 ShellApi, Windows;

var
 ShellExecuteInfo: TShellExecuteInfo;
 ParentProcessID: THandle;
begin
 if ParamCount = 1 then
 begin
   FillChar(ShellExecuteInfo, SizeOf(ShellExecuteInfo), 0);
   ShellExecuteInfo.cbSize := SizeOf(ShellExecuteInfo);
   ShellExecuteInfo.lpFile := PChar(ParamStr(1));
   ShellExecuteInfo.lpVerb := 'properties';
   ShellExecuteInfo.fMask := SEE_MASK_INVOKEIDLIST;
   GetWindowThreadProcessId(FindWindow('TAppBuilder', 'Delphi 5 - showprop'),
     @ParentProcessID);
   ShellExecuteInfo.hProcess := ParentProcessID;
   ShellExecuteEx(@ShellExecuteInfo);
   MessageBox(0, 'qwerty', 'qwerty', MB_OK);
 end; // else
end.

не канает с тем же результатом - окно свойств живет только до нажатия на ОК MessageBox'а...


nikkie   (2004-08-19 02:30:00) [6]

я посмотрел Spy++ - диалог принадлежит нашему процессу, просто создан он другим потоком. варианта вижу два - либо прицепиться к чужому процессу (идеально explorer.exe - и вызвать ShellExecute в его контексте), либо банально считать количество потоков при завершении программы и не выходить, пока их больше, чем 1.


R1   (2004-08-18 20:06:00) [7]

Оговорюсь - 1) на дуракоустойчивость пока забил, допустим, showprop.exe всегда вызывается с ровно одним параметром; 2) программа не обязательно консольная (на WriteLn просьба пристальное внимание не обращать :)).


R1   (2004-08-18 20:02:00) [8]

Как говорится, "все в порядке, идем ко дну, т. капитан!" :)

Вот как раз и хочется, чтобы диалог свойств файла оставался, пока лично его не закроют.

Кстати, о SHObjectProperties... Это какая-то странная функция, вообще... Сначала была совсем уж недокументирована, начиная с 5-ой версии shell32.dll она документирована, но по имени не вызывается, только по ординалу 178... В общем, вариант:

program showprop;

function SHObjectProperties(hWnd: LongWord; dwType: LongWord; szObject: Pointer;
 szPage: Pointer): LongBool; external 'shell32.dll' index 178;

const
 SHOP_FILEPATH = 2;

begin
 if ParamCount <> 1 then
   WriteLn('One and only parameter expected.')
 else
   SHObjectProperties(0, SHOP_FILEPATH, PChar(ParamStr(1)), nil);

   { // тот же результат, что и строчкой выше...
   SHObjectProperties(Windows.FindWindow('Progman', 'Program Manager'),
     SHOP_FILEPATH, PChar(ParamStr(1)), nil);
   }
end.

показывает диалог свойств какого-то неизвестного мне тома винчестера (с заголовком "Свойства: Том без метки", неизвестной файловой системой и с нулевыми емкостями)... Сам процесс showprop.exe при этом работает (в смысле, висит - в хорошем смысле - в памяти), пока этот диалог не закроют.

Таки как вызвать диалог свойств файла, закрыться - и чтоб этот диалог потом остался?


simpson   (2004-08-18 18:40:00) [9]

Извиняюсь... просмотрел, что приложение консольное.
Тогда все в порядке вещей - завершается приложение, закрывается окно свойств.


simpson   (2004-08-18 18:20:00) [10]

Попробуй так:


unit Unit1;

interface

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

const
 SHOP_PRINTERNAME = 1;
 SHOP_FILEPATH = 2;
 SHOP_VOLUMEGUID = 4;

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

var
 Form1: TForm1;

function SHObjectProperties(hOwnerWnd: HWND; dwType: DWORD;
 szObject, szPage: PWideChar): LongBool; stdcall;

implementation

function SHObjectProperties(hOwnerWnd: HWND; dwType: DWORD;
 szObject, szPage: PWideChar): LongBool;
 external 'shell32.dll' name 'SHObjectProperties';

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
 S: WideString;
begin
 S := Edit1.Text;
 if not SHObjectProperties(Application.Handle, SHOP_FILEPATH, PWideChar(S), nil) then
   ShowMessage('sorry...');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 Edit1.Text := ParamStr(0);
end;

end.


Наверх

Титульная страница Поиск, карта сайта Написать письмо