MS
|
|
« : 12-07-2007 09:35 » |
|
Подскажите как добавить в контекстное меню проводника пункт для запуска своего приложения.
|
|
|
Записан
|
Ничто так не ограничивает полёт мысли программиста, как компилятор
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #1 : 12-07-2007 09:39 » |
|
MS, вопрос неясен ) Может ты имеешь в виду меню Пуск ? Уточни...
потому что из контекстного меню проводника обычно вызываются инструменты (хотя, в принципе, это тоже ведь программы )
в любом случае - надо копаться в реестре.
|
|
|
Записан
|
|
|
|
MS
|
|
« Ответ #2 : 12-07-2007 09:51 » |
|
Алексей1153++, нужно чтобы привыделении файлов и клике на правую клавишу мыши в контекстном меню отображался пункт при щелчке на котором запускалась моя прога и в listbox добавлялись пути к выделенным файлам. Вот
|
|
|
Записан
|
Ничто так не ограничивает полёт мысли программиста, как компилятор
|
|
|
zubr
Гость
|
|
« Ответ #3 : 12-07-2007 14:11 » |
|
Этот вопрос решается через шелл. Набери в поисковике слово ShellExt и думаю, найдешь готовый пример.
|
|
|
Записан
|
|
|
|
MS
|
|
« Ответ #4 : 13-07-2007 06:05 » |
|
нашел стандартный пример в Delphi. Непонятна одна строка. Что она значит
Result := ExpandFileName(ReadString('RootDir') + '\bin\dcc32.exe');
|
|
|
Записан
|
Ничто так не ограничивает полёт мысли программиста, как компилятор
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #5 : 13-07-2007 06:29 » |
|
MS, всё решение в студию Нам же тоже интересно
|
|
|
Записан
|
|
|
|
zubr
Гость
|
|
« Ответ #6 : 13-07-2007 06:48 » |
|
Ms, это определение полного пути к файлу-компилятору Delphi (работающему из командной строки). Дело в том, что в этом примере из созданного пункта контекстного меню должен вызываться компилятор Delphi, который скомпилирует выделенный файл (естественно если это файл проекта Delphi). Алексей1153++, вот код примера: unit ContextM;
interface
uses Windows, ActiveX, ComObj, ShlObj, Dialogs;
type TContextMenu = class(TComObject, IShellExtInit, IContextMenu) private FFileName: array[0..MAX_PATH] of Char; protected { IShellExtInit } function IShellExtInit.Initialize = SEIInitialize; // Avoid compiler warning function SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject; hKeyProgID: HKEY): HResult; stdcall; { IContextMenu } function QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast, uFlags: UINT): HResult; stdcall; function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall; function GetCommandString(idCmd, uType: UINT; pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HResult; stdcall; end;
const Class_ContextMenu: TGUID = '{EBDF1F20-C829-11D1-8233-0020AF3E97A9}';
implementation
uses ComServ, SysUtils, ShellApi, Registry;
function TContextMenu.SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject; hKeyProgID: HKEY): HResult; var StgMedium: TStgMedium; FormatEtc: TFormatEtc; begin // Fail the call if lpdobj is Nil. if (lpdobj = nil) then begin Result := E_INVALIDARG; Exit; end;
with FormatEtc do begin cfFormat := CF_HDROP; ptd := nil; dwAspect := DVASPECT_CONTENT; lindex := -1; tymed := TYMED_HGLOBAL; end;
// Render the data referenced by the IDataObject pointer to an HGLOBAL // storage medium in CF_HDROP format. Result := lpdobj.GetData(FormatEtc, StgMedium); if Failed(Result) then Exit; // If only one file is selected, retrieve the file name and store it in // FFileName. Otherwise fail the call. if (DragQueryFile(StgMedium.hGlobal, $FFFFFFFF, nil, 0) = 1) then begin DragQueryFile(StgMedium.hGlobal, 0, FFileName, SizeOf(FFileName)); Result := NOERROR; end else begin FFileName[0] := #0; Result := E_FAIL; end; ReleaseStgMedium(StgMedium); end;
function TContextMenu.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast, uFlags: UINT): HResult; begin Result := 0; // or use MakeResult(SEVERITY_SUCCESS, FACILITY_NULL, 0);
if ((uFlags and $0000000F) = CMF_NORMAL) or ((uFlags and CMF_EXPLORE) <> 0) then begin // Add one menu item to context menu InsertMenu(Menu, indexMenu, MF_STRING or MF_BYPOSITION, idCmdFirst, 'Compile...');
// Return number of menu items added Result := 1; // or use MakeResult(SEVERITY_SUCCESS, FACILITY_NULL, 1) end; end;
function GetCompilerPath: string; // Returns string containing path to Delphi command line compiler var Reg: TRegistry; begin Reg := TRegistry.Create; try with Reg do begin RootKey := HKEY_LOCAL_MACHINE;
OpenKey('\SOFTWARE\Borland\Delphi\6.0', False); Result := ExpandFileName(ReadString('RootDir') + '\bin\dcc32.exe'); end; if AnsiPos(' ', Result) <> 0 then Result := ExtractShortPathName(Result); Result := Result + ' "%s"'; finally Reg.Free; end; end;
function TContextMenu.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; resourcestring sPathError = 'Error setting current directory';
var H: THandle; PrevDir: string; begin Result := E_FAIL; // Make sure we are not being called by an application if (HiWord(Integer(lpici.lpVerb)) <> 0) then begin Exit; end;
// Make sure we aren't being passed an invalid argument number if (LoWord(lpici.lpVerb) <> 0) then begin Result := E_INVALIDARG; Exit; end;
// Execute the command specified by lpici.lpVerb // by invoking the Delphi command line compiler. PrevDir := GetCurrentDir; try if not SetCurrentDir(ExtractFilePath(FFileName)) then raise Exception.CreateRes(@sPathError);
H := WinExec(PChar(Format(GetCompilerPath, [FFileName])), lpici.nShow);
if (H < 32) then MessageBox(lpici.hWnd, 'Error executing Delphi compiler.', 'Error', MB_ICONERROR or MB_OK); Result := NOERROR; finally SetCurrentDir(PrevDir); end; end;
function TContextMenu.GetCommandString(idCmd, uType: UINT; pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HRESULT; begin if (idCmd = 0) then begin if (uType = GCS_HELPTEXT) then // return help string for menu item StrCopy(pszName, 'Compile the selected Delphi project'); Result := NOERROR; end else Result := E_INVALIDARG; end;
type TContextMenuFactory = class(TComObjectFactory) public procedure UpdateRegistry(Register: Boolean); override; end;
procedure TContextMenuFactory.UpdateRegistry(Register: Boolean); var ClassID: string; begin if Register then begin inherited UpdateRegistry(Register);
ClassID := GUIDToString(Class_ContextMenu); CreateRegKey('DelphiProject\shellex', '', ''); CreateRegKey('DelphiProject\shellex\ContextMenuHandlers', '', ''); CreateRegKey('DelphiProject\shellex\ContextMenuHandlers\ContMenu', '', ClassID);
if (Win32Platform = VER_PLATFORM_WIN32_NT) then with TRegistry.Create do try RootKey := HKEY_LOCAL_MACHINE; OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions', True); OpenKey('Approved', True); WriteString(ClassID, 'Delphi Context Menu Shell Extension Example'); finally Free; end; end else begin DeleteRegKey('DelphiProject\shellex\ContextMenuHandlers\ContMenu'); DeleteRegKey('DelphiProject\shellex\ContextMenuHandlers'); DeleteRegKey('DelphiProject\shellex');
inherited UpdateRegistry(Register); end; end;
initialization TContextMenuFactory.Create(ComServer, TContextMenu, Class_ContextMenu, '', 'Delphi Context Menu Shell Extension Example', ciMultiInstance, tmApartment); end.
|
|
|
Записан
|
|
|
|
MS
|
|
« Ответ #7 : 13-07-2007 07:29 » |
|
zubr, откомпилировал проект, с dllкой что делать?
|
|
|
Записан
|
Ничто так не ограничивает полёт мысли программиста, как компилятор
|
|
|
zubr
Гость
|
|
« Ответ #8 : 13-07-2007 08:20 » |
|
Надо зарегистрировать сом-сервер. Для этого: 1. Создай батник с текстом: regsvr32.exe Твоя.dll 2. Сохрани его в каталог, где лежит твоя dll. 3. Запусти его. Если все правильно, в проводнике должен появиться новый пункт в контекстном меню.
|
|
|
Записан
|
|
|
|
MS
|
|
« Ответ #9 : 13-07-2007 08:51 » |
|
Все успешно компилируется, но пункт не появляется.Вот код. Исправьте пожалуйста что не так. unit ContextM;
interface
uses Windows, ActiveX, ComObj, ShlObj, Dialogs;
type TContextMenu = class(TComObject, IShellExtInit, IContextMenu) private FFileName: array[0..MAX_PATH] of Char; protected { IShellExtInit } function IShellExtInit.Initialize = SEIInitialize; // Avoid compiler warning function SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject; hKeyProgID: HKEY): HResult; stdcall; { IContextMenu } function QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast, uFlags: UINT): HResult; stdcall; function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall; function GetCommandString(idCmd, uType: UINT; pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HResult; stdcall; end;
const Class_ContextMenu: TGUID = '{EBDF1F20-C829-11D1-8233-0020AF3E97A9}';
implementation
uses ComServ, SysUtils, ShellApi, Registry;
function TContextMenu.SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject; hKeyProgID: HKEY): HResult; var StgMedium: TStgMedium; FormatEtc: TFormatEtc; begin // Fail the call if lpdobj is Nil. if (lpdobj = nil) then begin Result := E_INVALIDARG; Exit; end;
with FormatEtc do begin cfFormat := CF_HDROP; ptd := nil; dwAspect := DVASPECT_CONTENT; lindex := -1; tymed := TYMED_HGLOBAL; end;
// Render the data referenced by the IDataObject pointer to an HGLOBAL // storage medium in CF_HDROP format. Result := lpdobj.GetData(FormatEtc, StgMedium); if Failed(Result) then Exit; // If only one file is selected, retrieve the file name and store it in // FFileName. Otherwise fail the call. if (DragQueryFile(StgMedium.hGlobal, $FFFFFFFF, nil, 0) = 1) then begin DragQueryFile(StgMedium.hGlobal, 0, FFileName, SizeOf(FFileName)); Result := NOERROR; end else begin FFileName[0] := #0; Result := E_FAIL; end; ReleaseStgMedium(StgMedium); end;
function TContextMenu.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast, uFlags: UINT): HResult; begin Result := 0; // or use MakeResult(SEVERITY_SUCCESS, FACILITY_NULL, 0);
if ((uFlags and $0000000F) = CMF_NORMAL) or ((uFlags and CMF_EXPLORE) <> 0) then begin // Add one menu item to context menu InsertMenu(Menu, indexMenu, MF_STRING or MF_BYPOSITION, idCmdFirst, 'Добавить в Renamer');
// Return number of menu items added Result := 1; // or use MakeResult(SEVERITY_SUCCESS, FACILITY_NULL, 1) end; end;
function GetCompilerPath: string; // Returns string containing path to Delphi command line compiler var Reg: TRegistry; begin Reg := TRegistry.Create; try with Reg do begin RootKey := HKEY_LOCAL_MACHINE;
OpenKey('\SOFTWARE\Renamer\1.0', False); Result := ExpandFileName(ReadString('RootDir') + '\bin\dcc32.exe'); end; if AnsiPos(' ', Result) <> 0 then Result := ExtractShortPathName(Result); Result := Result + ' "%s"'; finally Reg.Free; end; end;
function TContextMenu.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; resourcestring sPathError = 'Error setting current directory';
var H: THandle; PrevDir: string;
begin Result := E_FAIL; // Make sure we are not being called by an application if (HiWord(Integer(lpici.lpVerb)) <> 0) then begin Exit; end;
// Make sure we aren't being passed an invalid argument number if (LoWord(lpici.lpVerb) <> 0) then begin Result := E_INVALIDARG; Exit; end;
// Execute the command specified by lpici.lpVerb // by invoking the Delphi command line compiler. PrevDir := GetCurrentDir; try if not SetCurrentDir(ExtractFilePath(FFileName)) then raise Exception.CreateRes(@sPathError);
H := WinExec(PChar(Format(GetCompilerPath, [FFileName])), lpici.nShow);
if (H < 32) then MessageBox(lpici.hWnd, 'Ошибка загрузки программы Renamer', 'Error', MB_ICONERROR or MB_OK); Result := NOERROR; finally SetCurrentDir(PrevDir); end; end;
function TContextMenu.GetCommandString(idCmd, uType: UINT; pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HRESULT; begin if (idCmd = 0) then begin if (uType = GCS_HELPTEXT) then // return help string for menu item StrCopy(pszName, 'Переименовать с помощью Renamer'); Result := NOERROR; end else Result := E_INVALIDARG; end;
type TContextMenuFactory = class(TComObjectFactory) public procedure UpdateRegistry(Register: Boolean); override; end;
procedure TContextMenuFactory.UpdateRegistry(Register: Boolean); var ClassID: string; begin if Register then begin inherited UpdateRegistry(Register);
ClassID := GUIDToString(Class_ContextMenu); CreateRegKey('Renamer\shellex', '', ''); CreateRegKey('Renamer\shellex\ContextMenuHandlers', '', ''); CreateRegKey('Renamer\shellex\ContextMenuHandlers\ContMenu', '', ClassID);
if (Win32Platform = VER_PLATFORM_WIN32_NT) then with TRegistry.Create do try RootKey := HKEY_LOCAL_MACHINE; OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions', True); OpenKey('Approved', True); WriteString(ClassID, 'Renamer'); finally Free; end; end else begin DeleteRegKey('Renamer\shellex\ContextMenuHandlers\ContMenu'); DeleteRegKey('Renamer\shellex\ContextMenuHandlers'); DeleteRegKey('Renamer\shellex');
inherited UpdateRegistry(Register); end; end;
initialization TContextMenuFactory.Create(ComServer, TContextMenu, Class_ContextMenu, '', 'Renamer', ciMultiInstance, tmApartment); end.
|
|
|
Записан
|
Ничто так не ограничивает полёт мысли программиста, как компилятор
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #10 : 13-07-2007 09:40 » |
|
MS, ребутнуть для начала надоть
|
|
|
Записан
|
|
|
|
MS
|
|
« Ответ #11 : 13-07-2007 11:36 » |
|
Алексей1153++, бестолку
|
|
|
Записан
|
Ничто так не ограничивает полёт мысли программиста, как компилятор
|
|
|
zubr
Гость
|
|
« Ответ #12 : 13-07-2007 14:33 » |
|
Надо твой Renamer связать с определенным типом файлов: procedure TContextMenuFactory.UpdateRegistry(Register: Boolean); var ClassID: string; begin if Register then begin inherited UpdateRegistry(Register);
ClassID := GUIDToString(Class_ContextMenu); CreateRegKey('.mytip', '', 'Renamer');//связываем CreateRegKey('Renamer\shellex', '', ''); CreateRegKey('Renamer\shellex\ContextMenuHandlers', '', ''); CreateRegKey('Renamer\shellex\ContextMenuHandlers\ContMenu', '', ClassID);
if (Win32Platform = VER_PLATFORM_WIN32_NT) then with TRegistry.Create do try RootKey := HKEY_LOCAL_MACHINE; OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions', True); OpenKey('Approved', True); WriteString(ClassID, 'Renamer'); finally Free; end; end else begin DeleteRegKey('.mytip'); DeleteRegKey('Renamer\shellex\ContextMenuHandlers\ContMenu'); DeleteRegKey('Renamer\shellex\ContextMenuHandlers'); DeleteRegKey('Renamer\shellex');
inherited UpdateRegistry(Register); end; end;
|
|
|
Записан
|
|
|
|
MS
|
|
« Ответ #13 : 14-07-2007 06:21 » |
|
zubr, спасибо разобрался. Осталось только одно. Подскажи как добавить выделенные файлы в listbox на форме
|
|
|
Записан
|
Ничто так не ограничивает полёт мысли программиста, как компилятор
|
|
|
zubr
Гость
|
|
« Ответ #14 : 14-07-2007 19:04 » |
|
Так а в чем проблема, в переменной FFileName и будет полное имя выделенного файла.
|
|
|
Записан
|
|
|
|
MS
|
|
« Ответ #15 : 15-07-2007 06:29 » |
|
zubr, тут вообще все очень странно. Когда я задаю типы файлов * или .*, dll не срабатывает, т.е. в реестре есть а в контекстном меню нет и удалить ее можно. Когда же задаю какой-либо определенный тип файла например .jpg, все отлично. Что делать? Неужели предется ко всем расширениям отдельно прописывать?
|
|
|
Записан
|
Ничто так не ограничивает полёт мысли программиста, как компилятор
|
|
|
zubr
Гость
|
|
« Ответ #16 : 15-07-2007 11:01 » |
|
Придется. Скорее всего это надо сделать программно, то есть программно просканировать реестр на типы файлов и для всех обнаруженных создать свои ключи.
|
|
|
Записан
|
|
|
|
|