Дамир дата публикации 29-10-2007 06:33 Блокирование документов при использовании TOleContainer.
Всем известно, что при использовании OleContainerа блокируются ранее открытые документы, и невозможно с ними ничего
сделать. Недавно встал вопрос: хорошо бы иметь возможность как-то разблокировать эти документы. Я по привычке полез в VCL и
вот что нашел: У объекта TOleContainer имеется внутренняя переменная FDocView, указывающая на интерфейс IOleDocumentView и
инициализирующаяся в начале активизации OleContainerа:
TOleContainer = class(TCustomControl, IUnknown, IOleClientSite,
IOleInPlaceSite, IAdviseSink, IOleDocumentSite, IOleUIObjInfo)
private
FDocView: IOleDocumentView;
В свою очередь, у интерфейса IOleDocumentView есть метод Show(fShow: BOOL):
IOleDocumentView = interface(IUnknown)
['{b722bcc6-4e68-101b-a2bc-00aa00404770}']
function Show(fShow: BOOL):HResult; stdcall;
Для "оживления" заблокированных документов, достаточно вызвать этот метод с параметром "false". Добавляем процедуру (или
функцию с возможностью обработки ошибок, кому как больше нравится) ShowView(fShow : boolean) в TOleContainer:
public
procedure ShowView(fShow : boolean);
и реализацию:
procedure TOleContainer.ShowView(fShow : boolean);
begin
if Pointer(FDocView) <> nil then
FDocView.Show(fShow);
end;
Для демонстрации работы создадим MDI приложение. Пусть дочернее окно содержит компонент OleContainer1 (Модуль, где
находится новый класс TOleContainer я назвал OleCtnrs_):
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, OleCtnrs_, StdCtrls, ExtCtrls, ExcelXP, ActiveX;
type
TForm2 = class(TForm)
procedure FormCreate(Sender: TObject);
private
OleContainer1: TOleContainer;
public
procedure OpenFile(FileName : string);
procedure DoDocShow;
procedure DoHideView;
end;
var
Form2: TForm2;
implementation
uses Unit1;
procedure TForm2.OpenFile(FileName : string);
begin
OleContainer1.CreateObjectFromFile(FileName, false);
DoDocShow;
end;
procedure TForm2.DoHideView;
begin
OleContainer1.ShowView(false);
end;
procedure TForm2.DoDocShow;
begin
OleContainer1.DoVerb(ovShow);
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
OleContainer1 := TOleContainer.Create(Self);
OleContainer1.Parent := Self;
OleContainer1.Align := alClient
end;
end.
Далее пишем родительское окно:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, OleCtnrs;
type
TForm1 = class(TForm)
GroupBox1: TGroupBox;
Button1: TButton;
OpenDialog1: TOpenDialog;
procedure Button1Click(Sender: TObject);
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
procedure WMKillFocus(var Message: TWMSetFocus); message WM_KILLFOCUS;
private
function GetViewActive : boolean;
public
property ViewActive : boolean read GetViewActive;
end;
var
Form1: TForm1;
implementation
uses Unit2;
function TForm1.GetViewActive : boolean;
begin
result := MDIChildCount <> 0;
end;
procedure TForm1.WMKillFocus(var Message: TWMSetFocus);
begin
if ViewActive then
begin
TForm2(MDIChildren[0]).DoDocShow;
end;
inherited;
end;
procedure TForm1.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
if ViewActive then
begin
TForm2(MDIChildren[0]).DoHideView;
end;
inherited;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
begin
with TForm2.Create(Application) do
begin
Visible := true;
OpenFile(OpenDialog1.FileName);
end;
end;
end;
end.
Программа работает следующим образом: Открывается, например, документ Excel. Затем запускается программа и открывается
другой документ Excel, но уже внутри OleContainerа. При переключении между Excelем и программой появляется возможность
работы с этими документами.
Программа работает со скрипом и скрежетом, но позволяет передавать фокус заблокированным документам. Может кому-то и
пригодится. Остальные методы интерфейса IOleDocumentView я не исследовал, поэтому, возможно есть другие, более красивые
решения.
[TOleContainer] [Использование OLE]
Обсуждение материала [ 07-10-2009 23:57 ] 2 сообщения |