Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Потрепаться";
Текущий архив: 2003.08.14;
Скачать: [xml.tar.bz2];

Вниз

Есть COM-расширение контекстного меню проводника от стороннего   Найти похожие ветки 

 
Alexander   (2003-05-25 09:06) [0]

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


 
nikkie   (2003-05-25 23:36) [1]

Можно. Ты хочешь воспользоваться одним вполне конкретным расширением? Надо научиться как-то его идентифицировать (например, найти в реестре его guid), чтобы знать, как его создать. В общем, надо получить интрефейс IContextMenu и вызвать метод InvokeCommand.


 
Alexander   (2003-05-26 08:12) [2]

Мне известно о нём всё, что нужно - GUID и все параметры
Буду копать в этом направлении.

А как получить этот интрефейс IContextMenu?


 
Polevi   (2003-05-26 09:55) [3]

D:\Program Files\Borland\Delphi6\Demos\ActiveX\ShellExt


 
Alexander   (2003-05-26 11:11) [4]

To Polevi:
по указанной ссылкеописано как создавать свои COM расширения, а мне нужно уже готовое расширение вставить в моё меню, а не в меню проводника


 
Polevi   (2003-05-26 13:27) [5]

var
cm:IContextMenu;
begin
cm:=CreateComObject(someGUID) as IContextMenu;
cm.QueryContextMenu(...


 
Alexander   (2003-05-26 15:58) [6]

В общем делаю так (взял для примера GUID WinRAR):

const
IID_DrWeb: TGUID = "{B41DB860-8EE4-11D2-9906-E49FADC173CA}";
var
CM: IContextMenu;
Menu, N: Cardinal;
begin
Menu := CreatePopupMenu;
CM := CreateComObject(IID_DrWeb) as IContextMenu;
N := CM.QueryContextMenu(Menu, 0, 0, $7FFF, CMF_NORMAL);
Caption := IntToStr(N);
if not TrackPopupMenu(Menu, TPM_LEFTALIGN or TPM_LEFTBUTTON or
TPM_RIGHTBUTTON or TPM_RETURNCMD, 10, 10, 0, 0, nil) then
begin
( hInstance, PChar(SysErrorMessage(GetLastError)
В общем делаю так (взял для примера GUID WinRAR):

const
IID_DrWeb: TGUID = "{B41DB860-8EE4-11D2-9906-E49FADC173CA}";
var
CM: IContextMenu;
Menu, N: Cardinal;
begin
Menu := CreatePopupMenu;
CM := CreateComObject(IID_DrWeb) as IContextMenu;
N := CM.QueryContextMenu(Menu, 0, 0, $7FFF, CMF_NORMAL);
Caption := IntToStr(N);
if not TrackPopupMenu(Menu, TPM_LEFTALIGN or TPM_LEFTBUTTON or
TPM_RIGHTBUTTON or TPM_RETURNCMD, 10, 10, 0, 0, nil) then
begin
MessageBox(hInstance, PChar(SysErrorMessage(GetLastError)), "", MB_OK);
end;
end;


но что-то не работает.
N=0, хотя по идее должно быть равно 1 (должен добавиться один пункт меню) и TrackPopupMenu хоть проходит без ошибок, но ничего не отображает


 
Polevi   (2003-05-26 17:52) [7]

мда, странно
для моего собственного класса все работает на ура,
для WinRar возвращает 0, для WinZip вообще ошибку в модуле выплевывает..


 
Набережных С.   (2003-05-26 19:03) [8]

Alexander © (26.05.03 15:58)

Если бы ты таким образом вызывал обработчик, написанный мной, то еще бы и AV получил. А нефиг потому что.


 
nikkie   (2003-05-27 01:40) [9]

>Набережных С.
зачем так сурово-то? ;)
но никто, конечно не обещал, что будет просто...

>Alexander, Polevi
если не работает, смотрим документацию :)

Context menu handlers are a type of shell extension handler. Like all such handlers, they are in-process COM objects implemented as dynamic-link libraries (DLLs). Context menu handlers must export two interfaces in addition to IUnknown: IShellExtInit and IContextMenu.

The IShellExtInit interface is used by the shell to initialize the handler. When the shell calls IShellExtInit::Initialize, it passes in a data object with the object"s name and the PIDL of the folder that contains the file. The hRegKey parameter is not used with context menu handlers. The IShellExtInit::Initialize method must extract the file name from the data object and store the name and the folder"s PIDL for later use.

вывод напрашивается сам собой - сначала надо вызвать IShellExtInit::Initialize. пример из ActiveX\ShellExt должен помочь разобраться с параметрами. только предупреждаю сразу - сам я такого не делал :)


 
Polevi   (2003-05-27 10:26) [10]

2nikkie © (27.05.03 01:40)
ты прав, забыл я про этот интерфейс
реализация его зависит от разработчика объекта, поэтому согласен с Набережных С, "нефиг" :)) хакерством попахивает


 
Alexander   (2003-05-27 10:26) [11]

А как мне получить экземпляр IShellExtInit ?


 
Alexander   (2003-05-27 10:29) [12]

Почему хакерство? Windows же посылает COM расширению стандартный набор команд для инициализации и отображения меню - его повторить (набор команд) не хакерство


 
Polevi   (2003-05-27 10:36) [13]

для получения указателя на интерфейс предназначен IUnknown::QueryInterface

var
unk:IUnknown;
CM: IContextMenu;
SEI:IShellExtInit;
begin
// получаем IUnknown объекта
unk:=CreateComObject(IID_DrWeb);
//объект реализует IContextMenu и IShellExtInit, для получения указателей на них вызываем QueryInterface
CM :=unk as IContextMenu;
SEI:=unk as IShellExtInit;

удачи


 
Alexander   (2003-05-27 11:43) [14]

Пытаюсь провести инициализацию: SEI.Initialize()
Parameters: (context menu or property sheet extension)
pidlFolder -- Specifies the parent folder
lpdobj -- Spefifies the set of items selected in that folder.
hkeyProgID -- Specifies the type of the focused item in the selection.

pidlFolder я получил используя процедуру из JCL:

function PathToPidlBind(const FileName: string; out Folder: IShellFolder): PItemIdList;
var
Attr, Eaten: ULONG;
PathIdList: PItemIdList;
DesktopFolder: IShellFolder;
Path, ItemName: TUnicodePath;
begin
Result := nil;
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, PChar(ExtractFilePath(FileName)), -1, Path, MAX_PATH);
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, PChar(ExtractFileName(FileName)), -1, ItemName, MAX_PATH);
if Succeeded(SHGetDesktopFolder(DesktopFolder)) then
begin
if Succeeded(DesktopFolder.ParseDisplayName(0, nil, Path, Eaten, PathIdList,
Attr)) then
begin
if Succeeded(DesktopFolder.BindToObject(PathIdList, nil, IID_IShellFolder,
Pointer(Folder))) then
begin
if FAILED(Folder.ParseDisplayName(0, nil, ItemName, Eaten, Result,
Attr)) then
begin
Folder := nil;
Result := DriveToPidlBind(FileName, Folder);
end;
end;
PidlFree(PathIdList);
end
else
( FileName, Folder)
Пытаюсь провести инициализацию: SEI.Initialize()
Parameters: (context menu or property sheet extension)
pidlFolder -- Specifies the parent folder
lpdobj -- Spefifies the set of items selected in that folder.
hkeyProgID -- Specifies the type of the focused item in the selection.

pidlFolder я получил используя процедуру из JCL:

function PathToPidlBind(const FileName: string; out Folder: IShellFolder): PItemIdList;
var
Attr, Eaten: ULONG;
PathIdList: PItemIdList;
DesktopFolder: IShellFolder;
Path, ItemName: TUnicodePath;
begin
Result := nil;
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, PChar(ExtractFilePath(FileName)), -1, Path, MAX_PATH);
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, PChar(ExtractFileName(FileName)), -1, ItemName, MAX_PATH);
if Succeeded(SHGetDesktopFolder(DesktopFolder)) then
begin
if Succeeded(DesktopFolder.ParseDisplayName(0, nil, Path, Eaten, PathIdList,
Attr)) then
begin
if Succeeded(DesktopFolder.BindToObject(PathIdList, nil, IID_IShellFolder,
Pointer(Folder))) then
begin
if FAILED(Folder.ParseDisplayName(0, nil, ItemName, Eaten, Result,
Attr)) then
begin
Folder := nil;
Result := DriveToPidlBind(FileName, Folder);
end;
end;
PidlFree(PathIdList);
end
else
Result := DriveToPidlBind(FileName, Folder);
end;
end;


А вот как мне получить два остальных параметра?


 
Polevi   (2003-05-27 11:49) [15]

последний не нужен


 
Alexander   (2003-06-05 13:16) [16]

В общем, смог я победить эту задачу. Делаю так:


procedure TForm1.Button2Click(Sender: TObject);
const
IID_IDataObject: TGUID = (D1:$0000010E;D2:$0000;D3:$0000;D4:($C0,$00,$00,$00,$00,$00,$00,$46));
IID_DrWeb: TGUID = "{1D1C35F6-EFCC-4E31-8B3C-109D5D3457FB}"; // Dr.Web
var
Menu: Cardinal;
Unk: IUnknown;
CM: IContextMenu;
SEI: IShellExtInit;
ItemIdList: PItemIdList;
Folder: IShellFolder;
DataObject: IDataObject;
begin
Menu := CreatePopupMenu;
ItemIdList := PathToPidlBind(Edit1.Text, Folder);
if Assigned(ItemIdList) then
try
Unk := CreateComObject(IID_DrWeb);
CM := Unk as IContextMenu;
SEI := Unk as IShellExtInit;

Folder.GetUIObjectOf(Handle, 1, ItemIdList, IID_IDataObject, nil, Pointer(DataObject));

SEI.Initialize(nil, DataObject, 0);
CM.QueryContextMenu(Menu, 0, 0, $7FFF, CMF_NORMAL);
TrackPopupMenu(Menu, TPM_LEFTALIGN or TPM_LEFTBUTTON or
TPM_RIGHTBUTTON or TPM_RETURNCMD, 10, 10, 0, Handle, nil);
finally
( ItemIdList)
В общем, смог я победить эту задачу. Делаю так:


procedure TForm1.Button2Click(Sender: TObject);
const
IID_IDataObject: TGUID = (D1:$0000010E;D2:$0000;D3:$0000;D4:($C0,$00,$00,$00,$00,$00,$00,$46));
IID_DrWeb: TGUID = "{1D1C35F6-EFCC-4E31-8B3C-109D5D3457FB}"; // Dr.Web
var
Menu: Cardinal;
Unk: IUnknown;
CM: IContextMenu;
SEI: IShellExtInit;
ItemIdList: PItemIdList;
Folder: IShellFolder;
DataObject: IDataObject;
begin
Menu := CreatePopupMenu;
ItemIdList := PathToPidlBind(Edit1.Text, Folder);
if Assigned(ItemIdList) then
try
Unk := CreateComObject(IID_DrWeb);
CM := Unk as IContextMenu;
SEI := Unk as IShellExtInit;

Folder.GetUIObjectOf(Handle, 1, ItemIdList, IID_IDataObject, nil, Pointer(DataObject));

SEI.Initialize(nil, DataObject, 0);
CM.QueryContextMenu(Menu, 0, 0, $7FFF, CMF_NORMAL);
TrackPopupMenu(Menu, TPM_LEFTALIGN or TPM_LEFTBUTTON or
TPM_RIGHTBUTTON or TPM_RETURNCMD, 10, 10, 0, Handle, nil);
finally
PidlFree(ItemIdList);
end;
DestroyMenu(Menu);
end;


Всё работает, но среди установленных у меня расширений одно не вызывается (DMEX menu). Может я что-то не учёл или не так делаю?


 
nikkie   (2003-06-05 14:47) [17]

пройдись дебаггером - что именно не работает? создается ли объект (не возвращает ли CreateComObject nil)? COM методы возвращают HRESULT, который можно обработать с помощью OleCheck. возвращает ли кто-нибудь из Folder.GetUIObjectOf, SEI.Initialize, CM.QueryContextMenu ошибку?

ЗЫ. нехорошо у тебя называется IID_DrWeb. сокращение IID означает interface ID. вот IID_IDataObject - это id интерфейса (он, кстати, в ole2.pas описан). а параметр в CreateComObject - class id. это разные вещи, так что назови лучше CLSID_DrWeb.


 
Alexander   (2003-06-05 15:54) [18]

CM.QueryContextMenu вылетает ошибкой - повторюсь только для одного из имеющихся у меня расширений, остальные работают отлично (DMEX в проводнике тоже работает отлично).
с переименованием IID_DrWeb согласен


 
nikkie   (2003-06-05 16:02) [19]

>CM.QueryContextMenu вылетает ошибкой
это я не понимаю. что за ошибка? Access Violation что ли?


 
Alexander   (2003-06-05 16:20) [20]

точно, Access Violation в dll расширения а всё до этого проходит без ошибок


 
nikkie   (2003-06-05 16:28) [21]

>без ошибок
то есть возвращаемые значения равны S_OK?
тебя пытать что ли надо, чтобы язык развязать?


 
Alexander   (2003-06-06 08:38) [22]

сделал я так:

OleCheck(Folder.GetUIObjectOf(Handle, 1, ItemIdList, IID_IDataObject, nil, Pointer(DataObject)));

OleCheck(SEI.Initialize(nil, DataObject, 0));
OleCheck(CM.QueryContextMenu(Menu, 0, 0, $7FFF, CMF_NORMAL));

и на строчке
( SEI.Initialize(nil, DataObject, 0) сделал я так:

OleCheck(Folder.GetUIObjectOf(Handle, 1, ItemIdList, IID_IDataObject, nil, Pointer(DataObject)));

OleCheck(SEI.Initialize(nil, DataObject, 0));
OleCheck(CM.QueryContextMenu(Menu, 0, 0, $7FFF, CMF_NORMAL));

и на строчке
OleCheck(SEI.Initialize(nil, DataObject, 0));
вываливается с сообщением "Неопознанная ошибка", другие расширения, как и ожидалось, работают и с проверкой


 
nikkie   (2003-06-06 15:07) [23]

уже лучше - понятно, где проблема.

упс... только сейчас заметил - почему у тебя первый параметр в Initialize nil? ты же собирался туда PIDL фолдера передавать?

кстати, MSDN дает какую-то противоречивую информацию о параметрах в Initialize.

(MSDN, январь 2000)
The hRegKey parameter is not used with context menu handlers

For context menu extensions, lpdobj identifies the selected file objects, hkeyProgID identifies the file class of the object with focus, and pidlFolder is not used.


(MSDN от VS.NET)
The hRegKey parameter is not used with shortcut menu handlers.

For shortcut menu extensions, lpdobj identifies the selected file objects, hkeyProgID identifies the file class of the object with focus, and pidlFolder is either NULL (for file objects) or specifies the folder for which the shortcut menu is being requested (for folder background shortcut menus).


думаю, надо взять пример ShellExt из demos и посмотреть, как же на самом деле эти параметры заполняет Windows.


 
Alexander   (2003-06-06 16:49) [24]

После тестирования параметров я получил, что первый параметр всегда передаётся nil - я его и стал так посылать только из-за того, что если его передавать не nil, то не работает.

В общем, третий параметр не нулевой передаётся, остаётся понять, что это такое, точнее как получить?


 
nikkie   (2003-06-06 18:58) [25]

HKEY hkeyProgID
Registry key for the file object or folder type.

по идее, это должен быть ключ реестра типа HKEY_CLASSES_ROOT\.doc
сам ты получить его сможешь с помощью RegOpenKeyEx, если будешь знать, какой именно ключ нужен. потом надо будет его закрыть через RegCloseKey.

можно ли получить из HKEY путь в реестре - по-моему, нет. но можно через RegEnumKeyEx перечислить детей и проверить догадку.


 
Alexander   (2003-06-09 11:08) [26]

Я нашёл этот ключ - для exe файла это HKEY_CLASSES_ROOT\exefile - я просто создал из расширения переменную и потом её нашёл, но проблеме это не помогло.
Расширение DMEX Menu не работает, можно было бы забить на него, но где вероятность того, что больше не попадётся таких расширений, ведь проводник его обрабатывает каким-то образом.


 
nikkie   (2003-06-09 15:47) [27]

>я просто создал из расширения переменную и потом её нашёл
я не понял ничего. покажи код.

>Я нашёл этот ключ - для exe файла это HKEY_CLASSES_ROOT\exefile
точно? тогда надо делать так: открыть ключ HKEY_CLASSES_ROOT\.exe (или какое там расширение), прочитать Default значение (в данном случае - exefile), открыть ключ HKEY_CLASSES_ROOT\exefile.


 
Alexander   (2003-06-10 08:35) [28]

В примере расширения я получил hkeyProgID и по этому ключу создал в реестре переменную и потом её нашёл. После этого я вручную открываю HKEY_CLASSES_ROOT\exefile и задаю это значение, но ...

Как надо делать - я знаю, просто я сейчас пытаюсь хотя-бы для какого-нибудь типа файлов вызвать это "упрямое" расширение


 
nikkie   (2003-06-10 15:14) [29]

>создал в реестре переменную и потом её нашёл
классная идея.

но у меня идеи кончились. может ты просто неправильно открываешь ключ? пробовал писать в реестр после того, как сам открыл ключ?

может Folder.GetUIObjectOf создает не совсем тот DataObject, который Windows передает в shell extension? можно попробовать перечислить форматы данных в них через EnumFormatEtc и сравнить.

и что это за штука - DMEX Menu? Кстати, какой именно HRESULT у тебя возвращает SEI.Initialize?


 
Alexander   (2003-06-10 21:18) [30]

>но у меня идеи кончились. может ты просто неправильно открываешь ключ?
>пробовал писать в реестр после того, как сам открыл ключ?
Пробовал, всё нормально

>и что это за штука - DMEX Menu?
Это расширение контекстного меню, добавляющее подменю с полезными возможностями, например: открыть окно DOS в выбранной папке, скопировать имена выбранных файлов и ещё многое другое

С этим расширением вообще интересно получается. Я тут для интереса решил попробовать из JCL процедуру DisplayContextMenu (я в общем оттуда и черпал первые навыки). Так вот, контекстное меню, которое она показывает, не содержит пункта DMEX! А в проводнике есть. Вот это уже загадка.

А SEI.Initialize возвращает -2147467259


 
nikkie   (2003-06-10 22:38) [31]

>А SEI.Initialize возвращает -2147467259
//
// MessageId: E_FAIL
//
// MessageText:
//
// Unspecified error
//
#define E_FAIL ( 0x80004005L)
>А SEI.Initialize возвращает -2147467259
//
// MessageId: E_FAIL
//
// MessageText:
//
// Unspecified error
//
#define E_FAIL _HRESULT_TYPEDEF_(0x80004005L)

да уж, дело темное. есть гениальная идея написать автору и спросить, что он там наворотил.

Contact : via e-mail to
andre.ruebel@urz.uni-heidelberg.de
Any hellos, hints and bug reports welcome ;)


 
Alexander   (2003-06-11 12:41) [32]

Да я уже пытался с ним связаться - письмо возвращается с сервера с сообщением "User unknown"

А вот ещё вопрос: есть у меня строка, содержащая CLSID, как мне это значение передать в переменную TGUID? Только не при описании переменной, а уже в процессе работы.


 
nikkie   (2003-06-11 15:30) [33]

StringToGUID из comobj.pas или api-функция CLSIDFromString



Страницы: 1 вся ветка

Форум: "Потрепаться";
Текущий архив: 2003.08.14;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.006 c
14-45074
Sergey Masloff
2003-07-27 11:33
2003.08.14
Proxies.dcu


14-45076
Sheng
2003-07-26 19:05
2003.08.14
А что, уже и краки сюда мона вылаживать?


14-45023
Evg12
2003-07-29 00:06
2003.08.14
Простой вопрос на который вы легко ответите


14-44983
nobody
2003-07-29 19:39
2003.08.14
переменная


14-45045
GROL
2003-07-26 21:20
2003.08.14
Нужен графический движок для CAD





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский