Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Кнопка в чужом приложении


Автор: RedArrow 28.9.2004, 09:22
Подскажите, пожалуйста, как добавить свою кнопку в чужое приложение? Например, в Outlook Express?

Автор: Georg4 28.9.2004, 09:37
Что ты имеешь под "Своей кнопкой". Совершенно левую кнопку или из стандартных кнопок приложения (как в Ворде) с твоими коммандами в неё заделанными

Автор: RedArrow 28.9.2004, 09:44
Можно стандартную, но что бы она выполняла мои функции. Либо, если это невозможно, то "совершенно левую", опять же, с моими функциями.

Автор: p0s0l 28.9.2004, 15:00
Создать кнопку можно так:
Код
wndBtn := CreateWindowEx (WS_EX_NOPARENTNOTIFY or WS_EX_TOPMOST, 'BUTTON', 'Test', WS_VISIBLE or WS_CHILDWINDOW,
           220, 62, 40, 29, wnd, 0, 0, nil);
Здесь wnd - хэндл окна, в котором будет создана кнопка. В данном случае создалась корявая такая кнопка, но ты можешь сделать и красивее... Почитай подробнее об CreateWindowEx, стилях и др...

Далее нужно сделать обработчик нажатия кнопки. Есть два пути, которые я тебе могу предложить:
1) Записать в виртуальное пространство чужого процесса свой обработчик.
2) Поставить ловушку (хук).

Немного расскажу про второй способ.
Делаем DLL примерно такого содержания:
Код
library HookDLL;

uses
 Windows, Messages, uGlobal;

{$R *.res}

function HookProc (nCode : integer; wP : WPARAM; lP : LPARAM) : LRESULT; stdcall;
var
 msg : ^CWPSTRUCT absolute lP;

begin
 OpenMap;
 if nCode >= 0 then
   if (msg.message = WM_COMMAND) and
      (msg.lParam = GlobalData.wndButton) then
     PostMessage (GlobalData.wndMain, WM_USER, msg.hwnd, msg.lParam);

 Result := CallNextHookEx (GlobalData.hook, nCode, wP, lP);
 CloseMap;
end;

function InstallHook (wnd : HWND; tid : DWORD; wndBtn : HWND) : HHOOK;
begin
 CreateMap;
 GlobalData.wndMain := wnd;
 GlobalData.hook := SetWindowsHookEx (WH_CALLWNDPROC, @HookProc, hInstance, tid);
 GlobalData.wndButton := wndBtn;
 Result := GlobalData.hook;
end;

procedure UninstallHook;
begin
 if GlobalData.hook <> 0 then UnhookWindowsHookEx (GlobalData.hook);
 CloseMap;
end;

exports
 InstallHook,
 UninstallHook;

end.
Вызов InstallHook установит ловушку, UninstallHook - уберёт хук.
При клике на кнопку хук проверяет, если нажали на созданную нами кнопку, то шлет сообщение WM_USER окну нашей проги.

Тут используется модуль uGlobal:
Код
unit uGlobal;

interface

uses windows;

type
 PGlobalData = ^TGlobalData;
 TGlobalData = record
   wndMain : HWND;
   hook : HHOOK;
   wndButton : HWND;
 end;

var
 hGlobalMap : THandle;
 GlobalData : PGlobalData;

const
 MapName = 'sharemap1';

procedure CreateMap;
procedure OpenMap;
procedure CloseMap;

implementation

procedure CreateMap;
begin
 if GlobalData <> nil then CloseMap;
 hGlobalMap := CreateFileMapping (INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, SizeOf(GlobalData^), MapName);
 GlobalData := MapViewOfFile (hGlobalMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
 ZeroMemory (GlobalData, SizeOf(GlobalData^));
end;

procedure OpenMap;
begin
 if GlobalData <> nil then CloseMap;
 hGlobalMap := OpenFileMapping (FILE_MAP_ALL_ACCESS, False, MapName);
 GlobalData := MapViewOfFile (hGlobalMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
end;

procedure CloseMap;
begin
 if GlobalData <> nil then UnmapViewOfFile (GlobalData);
 GlobalData := nil;
 if hGlobalMap <> 0 then CloseHandle (hGlobalMap);
 hGlobalMap := 0;
end;

end.
Этот модуль нужен типа для создания куска общедоступной памяти. В этой памяти хранится хэндл окна нашей проги, хэндл хука, и хэндл созданной кнопки.

Ну а дальше сам пример установки хука:
Код
unit Unit1;

interface

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

type
 TForm1 = class(TForm)
   Button1: TButton;
   procedure Button1Click(Sender: TObject);
   procedure FormCreate(Sender: TObject);
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
   procedure UserMessage (var msg : TMessage); message WM_USER;
 private
 public
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

var hook : HHOOK;

function InstallHook (wnd : HWND; tid : DWORD; wndBtn : HWND) : HHOOK; external 'HookDLL.dll';
procedure UninstallHook; external 'HookDLL.dll';

procedure TForm1.Button1Click(Sender: TObject);
var
 tid : DWORD;
 wnd, wndBtn : HWND;

begin
 ShellExecute (0, 'open', 'calc.exe', nil, nil, SW_SHOWNORMAL);
 Sleep(1000);
 
 wnd := FindWindow(nil, 'Calculator');
 if wnd = 0 then exit;
 tid := GetWindowThreadProcessId (wnd);
 wndBtn := CreateWindowEx (WS_EX_NOPARENTNOTIFY or WS_EX_TOPMOST, 'BUTTON', 'Test', WS_VISIBLE or WS_CHILDWINDOW,
           220, 62, 40, 29, wnd, 0, 0, nil);

 hook := InstallHook (Handle, tid, wndBtn);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 hook := 0;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 if hook <> 0 then UninstallHook;
end;

procedure TForm1.UserMessage (var msg : TMessage);
begin
 ShowMessage ('Clicked!');
end;

end.
Когда жмешь Button1 запустится калькулятор, и в нём создастся кнопка "Test".
Если нажмешь на эту кнопку, твоё приложение получит сообщение WM_USER, и выдаст сообщение...


Автор: Staszek 29.9.2004, 12:58
А про первый способ расскажи!!!

Автор: p0s0l 29.9.2004, 23:01
Цитата(Staszek @ 29.9.2004, 12:58)
А про первый способ расскажи!!!

А чем тебе второй не понравился ?... sad.gif
С первым _намного_ больше геморроя, так что лучше разберись с тем, что есть...

Автор: RedArrow 30.9.2004, 07:55
p0s0l
Спасибо, Ваша помощь пришлась как нельзя кстати.

Автор: Darksquall 30.9.2004, 08:42
А еще есть способ через OLE,
форму с кнопочкой создаешь заранее и вставляешь на форму OLE контейнер, указываешь в контейнере тип твоего приложения.
И все.
Я так сделал в ВОРДЕ, когда нужно было ограничить юзера в сохранении документа. т.е. он сохраняет документ только с помощью моей кнопки.А так все стандартные панели остались на месте.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)