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

Вниз

PlugIn для Internet Explorer   Найти похожие ветки 

 
hattak ©   (2010-11-11 13:46) [0]

Знаю, я уже надоел наверно некоторым со своими проблемами)) Но уже голову сломал просто)) Проблема, с написанием плагина для IE. Плагин должен быть в виде панельки с кнопками, а проблема следующая: если открыть несколько страниц в отдельных окнах (не заново запускать каждый раз IE, а именно окна новые - потомки от главного), то окна-потомки начинают "пересекаться" с главным окном, т.е. скажем в плагине есть переменная i:integer; в главном окне она имеет значение 2, так вот в окнах-потомках она тоже имеет это же значение сразу после их открытия ... более того, если в окне-потомке мы меняем это значение на 3, то в главном окне оно тоже меняется на 3 оО т.е. фактически все эти окна используют одну и ту же переменную, а нужно чтобы переменные в каждом новом окне были свои.
А то доходит до абсурда, в главном окне заголовок окна 111, после открытия потомка с заголовком 123, переменная из IWebBrowserApp.LocationName главного окна начинает говорить, что у главного окна заголовок именно 123, а не 111, как на самом деле(((

Далее, приведу код всего плагина, может я что-то где-то не так сделал?

----------------------------------- Интерфейсы -------------------------
unit Interfaces;

interface

uses ComObj, ShlObj, ActiveX, Classes, Windows, Messages, Shdocvw, ComServ,
    MainForm_Unit, ComCtrls;

const
 BandType = "{00021494-0000-0000-C000-000000000046}";

 Caption = "IE Plug-In";
 ToolBand = true;
 CLSID_DelphiBand: TGUID = "{3F5A62E2-51F2-11D3-A075-CC7364CAE42A}";
 MinX=121;
 MaxX=1024;
 IdealX=500;
 AllY=38;
type

 TIEPlugInFactory = class(TComObjectFactory)
 private
   procedure AddToRegistry;
   procedure RemoveFromRegistry;
 public
   procedure UpdateRegistry(Register: Boolean); override;
 end;

 TIEPlugInBar = class(TComObject, IDeskBand, IObjectWithSite)
 private
   HasFocus: Boolean;
   SavedWndProc: TWNDMethod;
   ParentWnd: HWND;
   Site: IInputObjectSite;
   cmdTarget: IOleCommandTarget;
   MForm: TMainForm;
 public
  // IDeskBand
   function GetWindow(out wnd: HWnd): HResult; stdcall;
   function ShowDW(fShow: BOOL): HResult; stdcall;
   function CloseDW(dwReserved: DWORD): HResult; stdcall;
   function GetBandInfo(dwBandID, dwViewMode: DWORD; var pdbi: TDeskBandInfo):HResult; stdcall;
   function ResizeBorderDW(var prcBorder: TRect; punkToolbarSite: IUnknown; fReserved: BOOL): HResult; stdcall;
   function ContextSensitiveHelp(fEnterMode: BOOL): HResult; stdcall;
   // IObjectWithSite
   function SetSite(const pUnkSite: IUnknown): HResult; stdcall;
   function GetSite(const riid: TIID; out site: IUnknown): HResult; stdcall;
   procedure FocusChange(bHasFocus: Boolean);
   procedure BandWndProc(var Message: TMessage);
   function MakeForm(wnd: HWnd): Boolean;
 end;

implementation

uses Registry;

function TIEPlugInBar.ContextSensitiveHelp(fEnterMode: BOOL): HResult;
begin
Result := E_NOTIMPL;
end;
function TIEPlugInBar.ShowDW(fShow: BOOL): HResult;
begin
Hasfocus:=fShow;
FocusChange(fShow);
Result := S_OK;
end;
function TIEPlugInBar.ResizeBorderDW(var prcBorder: TRect; punkToolbarSite: IUnknown;
fReserved: BOOL): HResult;
begin
Result := E_NOTIMPL;
end;

function TIEPlugInBar.GetBandInfo(dwBandID, dwViewMode: DWORD; var pdbi: TDeskBandInfo): HResult;
begin
if (pdbi.dwMask and DBIM_MINSIZE) <> 0 then
  begin
   pdbi.ptMinSize.x := MinX;
   pdbi.ptMinSize.y := AllY;
  end;
if (pdbi.dwMask and DBIM_MAXSIZE) <> 0 then
  begin
   pdbi.ptMaxSize.x := MaxX;
   pdbi.ptMaxSize.y := AllY;
 end;
if (pdbi.dwMask and DBIM_ACTUAL) <> 0 then
  begin
   pdbi.ptActual.x := IdealX;
   pdbi.ptActual.y := AllY;
 end;
if (pdbi.dwMask and DBIM_MODEFLAGS) <> 0 then
  begin
   pdbi.dwModeFlags := DBIMF_NORMAL;
  end;
if (Pdbi.dwMask and DBIM_TITLE) <> 0 then
  begin
   StringToWideChar(Caption, @pdbi.wszTitle, Length(Caption) + 1);
  end;
Result := NOERROR;
end;

procedure TIEPlugInBar.BandWndProc(var Message: TMessage);
begin
 if (Message.Msg = WM_PARENTNOTIFY)  then
 begin
   Hasfocus:=True;
   FocusChange(True);
 end;
 SavedWndProc(Message);
end;

function TIEPlugInBar.MakeForm(wnd: HWnd): Boolean;
begin
if not Assigned(MForm) then MForm := TMainForm.CreateParented(ParentWnd);
SavedWndProc := MForm.WindowProc;
MForm.WindowProc := BandWndProc;
Result := Assigned(MForm);
end;

function TIEPlugInBar.GetWindow(out wnd: HWnd): HResult;
begin
Wnd := MForm.Handle;
Result := S_OK;
end;

procedure TIEPlugInBar.FocusChange(bHasFocus: Boolean);
begin
 if (Site <> nil) then Site.OnFocusChangeIS(Self, bHasFocus);
end;

function TIEPlugInBar.SetSite(const pUnkSite: IUnknown): HResult;
var OleWind:IOleWindow;
   Provider:IServiceProvider;
begin
 if pUnkSite <> nil then
   begin
    pUnkSite.QueryInterface(IInputObjectSite,Site);
    if SUCCEEDED(pUnkSite.QueryInterface(IOleWindow,OleWind)) then
      begin
       OleWind.GetWindow(ParentWnd);
       MakeForm(ParentWnd);
       pUnkSite.QueryInterface(IOleCommandTarget,cmdTarget);
       CmdTarget.QueryInterface(IServiceProvider,Provider);
       Provider.QueryService(IWebbrowserApp, IWebbrowser2, IE);
     end;
   end;
 Result := S_OK;
end;


 
hattak ©   (2010-11-11 13:46) [1]

function TIEPlugInBar.GetSite(const riid: TIID; out site: IUnknown): HResult;
begin
 if Assigned(Site) then Result := Site.QueryInterface(riid, site)
 else Result := E_FAIL;
end;

function TIEPlugInBar.CloseDW(dwReserved: DWORD): HResult;
begin
if MForm <> nil then MForm.Destroy;
 Result := S_OK;
end;

procedure TIEPlugInFactory.UpdateRegistry(Register: Boolean);
begin
 inherited UpdateRegistry(Register);
 if Register then AddToRegistry else RemoveFromRegistry;
end;

procedure TIEPlugInFactory.AddToRegistry;
var  S:string;
begin
 S := GUIDToString(CLSID_DelphiBand);
 with TRegistry.Create do
 try
  RootKey := HKEY_CLASSES_ROOT;
  if OpenKey("CLSID\" + S, True) then
    begin
     WriteString("", "&IE Plug-In");
     CloseKey;
    end;
  if OpenKey("CLSID\" + S + "\InProcServer32", True) then
    begin
     WriteString("ThreadingModel", "Apartment");
     CloseKey;
    end;
  if OpenKey("CLSID\" + S + "\Implemented Categories\" + BandType, True) then CloseKey;
  if ToolBand then
    begin
     RootKey := HKEY_LOCAL_MACHINE;
     if OpenKey("SOFTWARE\Microsoft\Internet Explorer\Toolbar", True) then
       begin
        WriteString(S, "");
        CloseKey;
       end;
    end;
 finally
  Free;
 end;
end;

procedure TIEPlugInFactory.RemoveFromRegistry;
var S: string;
begin
 S := GUIDToString(CLSID_DelphiBand);
 with TRegistry.Create do
 try
   RootKey := HKEY_CLASSES_ROOT;
   DeleteKey("Component Categories\" + BandType + "\Enum");
   DeleteKey("CLSID\" + S + "\Implemented Categories\" + BandType);
   DeleteKey("CLSID\" + S + "\InProcServer32");
   DeleteKey("CLSID\" + S);
   Closekey;
   if ToolBand then
     begin
      RootKey := HKEY_LOCAL_MACHINE;
      OpenKey("Software\Microsoft\Internet Explorer\Toolbar", FALSE);
      DeleteValue(S);
      CloseKey;
      DeleteKey("Software\IEPlugIn");
      CloseKey;
    end;
 finally
   Free;
 end;
end;

initialization
 TIEPlugInFactory.Create(ComServer, TIEPlugInBar, CLSID_DelphiBand, "", Caption, ciMultiInstance);
end.

----------------------------------- Панелька  -------------------------

unit MainForm_Unit;

тут ничего интересного, обычное окно MainForm = class(TForm) на окне кнопка, в глобальных переменных только var i:integer;

ну и

library haddan_ie_plugin;

uses
 ComServ,
 Interfaces in "Interfaces.pas",
 MainForm_Unit in "MainForm_Unit.pas" {MainForm};

exports DllGetClassObject,
       DllCanUnloadNow,
       DllRegisterServer,
       DllUnregisterServer;

{$R *.TLB}

{$R *.res}

begin
end.

Может кто-то знает, в чём может быть дело?, а то всё очень печально получается((( подскажите пожалуйста)


 
crux   (2010-11-11 15:42) [2]

>в плагине есть переменная i:integer;

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

>переменная из IWebBrowserApp.LocationName главного окна

Как получается IWebBrowserApp?


 
hattak ©   (2010-11-11 15:59) [3]

да, я это знаю, поэтому я пробовал сделать класс, скажем

TMyClass = class
i:integer;
end;

хммм ... хотя, конечно всё равно
var My:TMayClass; глобальная получается ...

IWebBrowserApp из IE, т.е. интерфейса IWebBrowser2,
полученного при вызове SetSite
var wbApp:IWebBrowserApp;
......
IE.QueryInterface(IWebBrowserApp,wbApp);
......
ну и wbApp.LocationName

а как же быть, куда "запрятать" переменные, чтоб они небыли глобальними,
но при этом я имел к ним доступ из других окон плагина.
дело в том, что в плагине несколько окон создаётся, я тут их просто не прописал в примере, т.к. это громозко будет
Но если я прячу переменные в класс TMainForm, ну как бы делаю их не глобальными и пытаюсь потом получить их из другого окна плагина как MainForm.переменная, то это приводит к ошибке сразу же, там приложение вызвало ошибку ... адрес памяти дан и т.п.


 
hattak ©   (2010-11-11 16:02) [4]

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


 
crux   (2010-11-11 16:31) [5]

hattak ©   (11.11.10 15:59) [3]

>а как же быть, куда "запрятать" переменные, чтоб они небыли глобальними,

Первое пришедшее на ум быстрое и гразное решение: какая-нибудь глобальная хэш-таблица вида id окна -> данные окна (нужна синхронизация).

>то это приводит к ошибке сразу же, там приложение вызвало ошибку ... адрес памяти дан и т.п.

Это уже странно, но вообще, данные, которые должны разделяться, нужно сделать доступными через COM-интерфейс и обращаться к ним только через него. Скорее всего, ошибка происходит из-за того, что объекты находятся в разных апартаментах (созданы разными потоками), и для доступа к данным другого объекта нужно маршаллить COM-интерфейс (попробуй посмотреть CoMarshalInterThreadInterfaceInStream).


 
hattak ©   (2010-11-11 16:56) [6]

да, я тоже подумал о том, что они в разных комнатах
потому что получается, что всё, что расположено на окне MainForm, скажем кнопка или там TToolBar, TPopup невозможно изменить из других окон, но возможно из самого MainForm ...

новые окна плагина я создавал уже после создания главного окна,
т.е. MainForm создаётся при вызове SetSite, а остальные в onCreate самого MainForm"а. если я создам все окна в SetSite, тогда они должны быть в одной комнате, наверно? (спрашиваю, т.к. в данный момент, не могу проверить, нет прав на regsvr32 сейчас:)))) )

так, а про id окна ... а как же его взять если у меня основной интерфейс окна - IE (IWebBrowser2) при создании каждого потомка изменяется и фактически берётся от этого потомка. может запомнить, скажем заголовок окна при его открытии и его хэндл и потом искать по findwindow. Хэндлы-то хоть у потомков отличаются от родителя?)))


 
han_malign   (2010-11-12 09:02) [7]


> а остальные в onCreate самого MainForm"а.

- а ссылку на MainForm ты где берешь? Надеюсь передаешь  потомку при создании?

> объекты находятся в разных апартаментах

З.Ы. Какой нахрен маршалинг внутри монолитной реализации...


 
crux   (2010-11-12 09:39) [8]

>З.Ы. Какой нахрен маршалинг внутри монолитной реализации...

Для вызовов через границы апартаментов все равно нужно создавать прокси-интерфейс для синхронизации, для чего и используется маршалинг.


 
han_malign   (2010-11-12 11:00) [9]


> Для вызовов через границы апартаментов все равно нужно создавать
> прокси-интерфейс для синхронизации, для чего и используется
> маршалинг.

- откуда возьмутся границы апартаментов - при прямом вызове метода объекта из одного сегмента кода(независимо от контекста потока, до тех пор пока не происходит обращение к Внешнему Интерфейсу)?

Маршалинг в большинстве случаев прозрачно делается системой. Чуть ли не единственное исключение - обращение к уже отмаршализованному заместителю, при этом заместитель честно вернет RPC_E_WRONG_THREAD...
Правда, автор - стойкий партизан, которому партийная идеология не позволяет признаться, что это за "ошибка ... адрес памяти дан и т.п.". Хотя на 90% уверен, что это AV при обращении к глобальной ссылке MainForm которая имеет осмысленное значение(nil) только потому, что находится в .bss сегменте данных...


 
hattak ©   (2010-11-12 21:39) [10]

автор не партизан, автор только что добрался до компа.
значит создание всех форм "в одном месте" при вызове SetSite ничего не дал тоде самое ...

объясняю подробнее
на TMainForm скажем лежит TToolBar с кнопками, так вот если я обращаюсь к ним или вообще к чему угодно, принадлежащему классу TMainForm как MainForm.обращение (ну, скажем MainForm.TB1.Down := true; если TB1 есть кнопка TToolBar"а) то это вызывает ошибку
http://i079.radikal.ru/1011/38/d2c8a2f48729.jpg
и так при попытке обращения любым элементом, а вот если обратиться TB1.Down := true; то всё хорошо
но если тот же ToolBar с кнопками создать динамически на onCreate MainForm, то всё хорошо, ошибок нет ...


 
han_malign   (2010-11-13 15:22) [11]

ну я ж говорил AV...

еще раз для тех кто читает через строку:
function TIEPlugInBar.MakeForm(wnd: HWnd): Boolean;
begin
  if not Assigned(MForm) then MForm := TMainForm.CreateParented(ParentWnd);
  SavedWndProc := MForm.WindowProc;
  MForm.WindowProc := BandWndProc;
  Result := Assigned(MForm);
end;


в MainForm - nil, а "address 00000314" - это, по сути, смещение поля TMainForm которому ты пытаешься обратиться...


 
han_malign   (2010-11-13 15:32) [12]

сразу:
1. MainForm - глобальная переменная, а то что ими нельзя пользоваться мы уже знаем.
2. У каждого компонента есть свойство Owner которое соответствует тому что было указано в конструкторе при создании. Так вот, зная структуру иерархии компонент, это поле надо тупо привести к нужному типу. Можно также явным образом во всех дочерних компонентах завести поле FRoot: TMainForm, естественно в него нужно прописать нужную ссылку при создании компонента. "в onCreate самого MainForm"а" - эта ссылка хранится в переменной self...


 
han_malign   (2010-11-13 15:42) [13]

ну и, чтобы расставить все точки над i:
 - в обычном приложении, созданном с помощью мастера, глобальная переменная MainForm инициализируется в <...>.dpr:

program ...;
 ...
begin
 Application.Initialize;
 Application.CreateForm(TMainForm, MainForm);
 Application.Run;
end.


 
hattak ©   (2010-11-13 18:20) [14]

2 han_malign
Огромное спасибо! Дело было именно в этом, я совсем слепой((
Убрал MForm вообще и в интерфейсе просто создаю MainForm
Остальные формы тоже создаю в SetSite после создание MainFrom, тогда всё работает, доступ к компонентам есть. Проверил, если создавать новые окна на onCreate MainForm"а тогда не работает, опять та же  ошибка сразу, а Owner доступен только на чтение ... ну это и не нужно как бы, при последовательном создании MainForm, .... другие .... всё хорошо))

Так, а с переменными глобальными - я вот долго смотрел, что же происходит и очень интересно получается. Значит вот у нас есть главное окно, в нём ссылка, открывающаяся в окне-потомке, нажимаем ... открывается потомок, НО у него переменные свои, т.е. он не пересекается в главным и работает нормально! Потом из этого потомка открываю ещё одно окно, т.е. как бы потомок потомка и вот здесь, этот потомок2 (главное->потомок1->потомок2) пересекается с главным, т.е. его переменные = переменные главного окна.
Тут вот и не понятно, если бы все глобальные переменные родителя использовались всеми потомками, тогда было бы понятно, а тут получается прямой потомок главного окна имеет свои переменные, а вот потомок потомка имеет общие переменные с главным оО


 
han_malign   (2010-11-15 17:27) [15]


> onCreate MainForm"а тогда не работает

- ключевые слова on и Create...
ссылка в MainForm присваивается после выполнения TMainForm.Create...

> а Owner доступен только на чтение

- а нахрена тебе перезаписывать указатель на владельца??? Тебе его нужно привести к необходимому типу и обратиться к необходимым полям/методам...

> Тут вот и не понятно, если бы все глобальные переменные
> родителя использовались всеми потомками

- каждый последующий потомок перезаписывает глобальную переменную, в результате в конце все ссылаются на последний и если он "умрет" раньше остальных - будет большой ОЙ...


 
hattak ©   (2010-11-15 22:31) [16]


> - каждый последующий потомок перезаписывает глобальную переменную,
>  в результате в конце все ссылаются на последний и если
> он "умрет" раньше остальных - будет большой ОЙ...

да это я понимаю))
я не понимаю, как их сделать не глобальными.
мы тут говорили про то, чтобы создать таблицу и хранить там какие-то идентификаторы окон, ну может их заголовки или хендлы
но не получается, т.е. да, вот создалось первое окно за скажем заношу его хендл в переменную ... но когда создаётся новое окно я же теряю все переменные старого, включая хендл, т.к. эта "глобальная таблица", хранящая идентификатор также будет перезаписана, ну пересоздана точнее ... так как же тут быть-то?


 
hattak ©   (2010-11-15 22:36) [17]

ведь даже если я запихну переменную в TMainForm, переменная MainForm всё равно будет глобальной или любая другая будет глобальной и пересоздатся при создании нового окна ... вообще не понимаю, как же можно их "изолировать" оО


 
han_malign   (2010-11-16 10:08) [18]

млин, снимись с ручника - у тебя есть корневой объект ассоциированный с панелью IE, у IE - есть на него ссылка, у всех его дочерних компонент - ЕСТЬ на него ссылка (через Owner[.Owner[...]]) - нахрена тебе еще и ассоциативная таблица???



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

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

Наверх





Память: 0.53 MB
Время: 0.004 c
15-1290100289
Mitroshin
2010-11-18 20:11
2011.02.27
Несколько вопросов по переходу с D7 на D2010 (литература)


2-1291285177
Свободный художник
2010-12-02 13:19
2011.02.27
работа с форматом dwg, конертация bmp в dwg и обратно


2-1291789646
Nickolay
2010-12-08 09:27
2011.02.27
Операции с классами


15-1289322690
blacky1979
2010-11-09 20:11
2011.02.27
Посоветуйте компонет для отрисовки кинозала


11-1206640025
arthur
2008-03-27 20:47
2011.02.27
app crashing when sysutils exceptions are trowed





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский