Форум: "Прочее";
Текущий архив: 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