2016-06-22 7 views
2

Я следую за How to call Delphi code from scripts running in a TWebBrowser Учебник DelphiDabbler (от Peter Johnson), чтобы позволить Delphi прослушивать TWebBrowser события JavaScript.Расширение внешнего объекта TWebBrowser для выполнения кода Delphi: как получить доступ к моим компонентам формы?

Это работает до такой степени, что я вижу, что мои процедуры Delphi вызываются. Однако оттуда мне нужно обновить некоторые ярлыки формы, и я не вижу доступа к моей форме из этих процедур.
Пример кода DelphiDabbler хорошо обходит «прямой доступ формы» по creatingTHintAction.Create(nil);, который будет делать это дело:

Это давайте нам отвязать нашу внешнюю реализацию объекта весьма приятно от формы программы

Но я хочу получить доступ к моей форме! Передаваемые данные представляют собой целые числа и строки.
Я мог бы использовать сообщения PostMessage() и WM_COPYDATA, но им все равно нужен дескриптор формы. И нет ли «прямого» пути к форме?

Соответствующий код:

type 
    TWebBrowserExternal = class(TAutoIntfObject, IWebBrowserExternal, IDispatch) 
    protected 
     procedure SetVanLabel(const ACaption: WideString); safecall; // My 3 procedures that are called... 
     procedure SetNaarLabel(const AValue: WideString); safecall; // ... declared in the type library. 
     procedure SetDistanceLabel(AValue: Integer); safecall; 
    public 
     constructor Create; 
     destructor Destroy; override; 
    end; 

type 
    TExternalContainer = class(TNulWBContainer, IDocHostUIHandler, IOleClientSite) 
    private 
     fExternalObj: IDispatch; // external object implementation 
    protected 
     { Re-implemented IDocHostUIHandler method } 
     function GetExternal(out ppDispatch: IDispatch): HResult; stdcall; 
    public 
     constructor Create(const HostedBrowser: TWebBrowser); 
    end; 

constructor TExternalContainer.Create(const HostedBrowser: TWebBrowser); 
begin 
    inherited Create(HostedBrowser); 
    fExternalObj := TWebBrowserExternal.Create; 
end; 

Форма имеет property FContainer: TExternalContainer;, в FormCreate я fContainer := TExternalContainer.Create(WebBrowser); (параметр времени дизайн TWebBrowser), поэтому TExternalContainer.fExternalObj назначен к этому.

Вопрос:

procedure TWebBrowserExternal.SetDistanceLabel(AValue: Integer); 
    begin 
    // **From here, how do I send AValue to a label caption on my form?** 
    end; 

Я должен признать, что интерфейсы не моя сильная сторона ;-)

[Добавлено:] Примечание: Мои формы все созданные динамически, нет ни одного случая ТГогт в текущий блок.

+0

если вы возвращаете форму ручки в TWebBrowserExternal, как функции GetformHandle(): Word? – Passella

+0

Можно использовать [более простой подход для реализации внешних методов в Delphi] (http://stackoverflow.com/a/22184159/859646), используя поздние функции, предоставляемые ObjComAuto.TObjectDispatch. Таким образом, вам не нужно определять какие-либо интерфейсы или библиотеку типов. – JRL

ответ

1

Принимая советы Вы говорите, что хотите получить доступ к форме, но на самом деле нет - по крайней мере, не напрямую из DSm в his/her answer, я решил использовать PostMessage/SendMessage (как я намекал на в моем вопросе).

Сначала я передать дескриптор окна в конструкторах TWebBrowserExternal и TExternalContainer и хранить его в качестве частной собственности:

type 
    TWebBrowserExternal = class(TAutoIntfObject, IWebBrowserExternal, IDispatch) 
    private 
     fHandle: HWND; 
     procedure SendLocationUpdate(AWhere: Integer; ALocation: String); // Helper for SetVanLabel/SetNaarLabel 
    protected 
     procedure SetVanLabel(const AValue: WideString); safecall; 
     procedure SetNaarLabel(const AValue: WideString); safecall; 
     procedure SetDistanceLabel(AValue: Integer); safecall; 
    public 
     constructor Create(AHandle: HWND); 
     destructor Destroy; override; 
    end; 

type 
    TExternalContainer = class(TNulWBContainer, IDocHostUIHandler, IOleClientSite) 
    private 
     fExternalObj: IDispatch; // external object implementation 
    protected 
     { Re-implemented IDocHostUIHandler method } 
     function GetExternal(out ppDispatch: IDispatch): HResult; stdcall; 
    public 
     constructor Create(const HostedBrowser: TWebBrowser; AHandle: HWND); 
    end; 

В FormCreate TExternalContainer теперь создан как

fContainer := TExternalContainer.Create(WebBrowser, Self.Handle); 

Set... методы реализованы как:

procedure TWebBrowserExternal.SetDistanceLabel(AValue: Integer); 
begin 
    PostMessage(fHandle,UM_UPDATEDIST,AValue,0); // const UM_UPDATEDIST = WM_USER + 101; 
end; 

procedure TWebBrowserExternal.SetNaarLabel(const AValue: WideString); 
begin 
    SendLocationUpdate(1,AValue); 
end; 

procedure TWebBrowserExternal.SetVanLabel(const AValue: WideString); 
begin 
    SendLocationUpdate(0,AValue); 
end; 

с вспомогательной функцией:

procedure TWebBrowserExternal.SendLocationUpdate(AWhere: Integer; ALocation: String); 
var lCopyDataStruct: TCopyDataStruct; 
begin 
    lCopyDataStruct.dwData := AWhere; 
    lCopyDataStruct.cbData := 2 * 2 * Length(ALocation); 
    lCopyDataStruct.lpData := PChar(ALocation); 
    SendMessage(fHandle, WM_COPYDATA, wParam(fHandle), lParam(@lCopyDataStruct)); 
end; 

Моя форма содержит два обработчика сообщений, которые действительно обновляют метки:

procedure UpdateDistMsgHandler(var Msg: TMessage); message UM_UPDATEDIST; 
procedure WMCopyData(var Msg : TWMCopyData) ; message WM_COPYDATA; 

procedure TFrmGoogleMapsLiveUpdate.UpdateDistMsgHandler(var Msg: TMessage); 
begin 
    LabelDistance.Caption := IntToStr(Msg.WParam); 
end; 

procedure TFrmGoogleMapsLiveUpdate.WMCopyData(var Msg: TWMCopyData); 
var 
    lWhere : integer; 
    lLocation : string; 
begin 
    lWhere := Msg.CopyDataStruct.dwData; 
    lLocation := String(PChar(Msg.CopyDataStruct.lpData)); 
    if lWhere = 0 then 
     LabelVan.Caption := lLocation 
    else 
     LabelNaar.Caption := lLocation; 
end; 
1

Вы говорите, что хотите получить доступ к своей форме, но на самом деле нет - по крайней мере, не напрямую. Вы действительно хотите «отделить нашу реализацию внешнего объекта от формы программы». Все, что вам нужно сделать, это написать функцию или процедуру, чтобы делать то, что вы хотите в своей программе, а затем вызвать эту функцию или процедуру из своего веб-браузера. Это то, что касается развязки и интерфейсов. You never обрабатывать данные, принадлежащие одному приложению, напрямую от другого. Вместо этого вы используете в качестве интерфейса функции и процедуры. Кстати, именно поэтому интерфейсы содержат только прототипы функций и процедур (и свойства - но они только что переведены как функции и процедуры) - никогда не данные.

Теперь до вашего конкретного вопроса. Конечно, вы можете получить доступ к своей форме - это глобальная переменная. Предположим, что ваша главная форма имеет тип TMainForm в блоке под названием Main.pas, будет глобальная переменная с именем MainForm

var 
    MainForm : TMainForm; 

так в вашем WebBrowser блока, в секции реализации вы положили бы

implementation 

uses Main; 

... 

procedure TWebBrowserExternal.SetDistanceLabel(AValue: Integer); 
begin 
    // **From here, how do I send AValue to a label caption on my form?** 
    FormMain.MyLabel.Caption := StrToInt(AValue); 
end; 

В контексте того, что я сказал, SetDistanceLabel - это функция интерфейса, и форма доступна только из приложения Delphi.

+0

А, прости, я должен был сказать, что у меня есть только формы, которые создаются динамически (обновляя мой вопрос). Это не значит, что я не могу получить к ним доступ, но мне придется искать их. Но я беру ваш совет о развязке. –

+0

Тот же принцип применяется. Дело в отношении «uses» в реализации заключалось в том, что я не ожидал, что форма будет в одном блоке. Это стандартный способ обойти рекурсию с помощью единиц. При необходимости используйте глобальную переменную Application (в VCL.Forms или FMX.Forms, если необходимо), чтобы найти нужную форму. – Dsm

 Смежные вопросы

  • Нет связанных вопросов^_^