提个比较难的问题:关于WORD中存盘的消息。 (200分)

  • 主题发起人 主题发起人 荷塘新月
  • 开始时间 开始时间
procedure InterfaceConnect(const Source: IUnknown; const IID: TIID; const Sink: IUnknown; var Connection: Longint);

Description

Call InterfaceConnect from a client application to register an object that implements an outgoing server connection. Typically, this object is an event sink that a client uses to respond to server events. When an event occurs, the server (event source) calls its outgoing interface for the event, and the client, which implements the interface as an event sink, receives the call

InterfaceConnect obtains an IConnectionPoint interface from a COM server advising on a particular connection point. IConnectionPoint lets the server expose an outgoing interface for an object, typically an event sink. IConnectionPointContainer enumerates the connection points supported by the server, so that a caller can find the right connection point. The IConnectionPointContainer and IConnectionPoint interfaces comprise the standard COM event-handling mechanism.

Source is an IUnknown interface for the server object that defines and calls the outgoing interface.

IID is the GUID of the outgoing interface.

Sink is the IUnknown interface of the client object that implements the outgoing interface.

Connection returns a token that represents the connection. It must be saved for use by the InterfaceDisconnect procedure that is called to terminate the connection established by calling InterfaceConnect.

Note: A demo containing this procedure resides in Demos/ActiveX directory.


//待续...........
 
以下是DELPHI自带的DEMO,我添加了几行代码,后面带//添加
工程文件参照DEMO就可以了,添加个SAVE过程就可以了。



unit AutoImpl;

interface

// This Demo excersises the use of ActiveX Automation using Early Binding.

uses
Windows, Classes, ActiveX, Word97;

type
TWordEventSink = class(TInterfacedObject, IUnknown, IDispatch)
private
FOwner : TObject;
FAppDispatch: IDispatch;
FDocDispatch: IDispatch;
FAppDispIntfIID: TGUID;
FDocDispIntfIID: TGUID;
FAppConnection: Integer;
FDocConnection: Integer;
FOnQuit : TNotifyEvent;
FOnDocumentChange : TNotifyEvent;
FOnNewDocument : TNotifyEvent;
FOnOpenDocument : TNotifyEvent;
FOnCloseDocument : TNotifyEvent;
FOnSaveDocument : TNotifyEvent; //添加
protected
{ IUnknown }
function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
{ IDispatch }
function GetTypeInfoCount(out Count: Integer): HRESULT; stdcall;
function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HRESULT; stdcall;
function GetIDsOfNames(const IID: TGUID; Names: Pointer;
NameCount, LocaleID: Integer; DispIDs: Pointer): HRESULT; stdcall;
function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HRESULT; stdcall;
public
constructor Create(AnOwner: TObject; AnAppDispatch: IDispatch; const AnAppDispIntfIID, ADocDispIntfIID: TGUID);
destructor Destroy; override;
property OnQuit : TNotifyEvent read FOnQuit write FOnQuit;
property OnDocumentChange : TNotifyEvent read FOnDocumentChange write FOnDocumentChange;
property OnNewDocument : TNotifyEvent read FOnNewDocument write FOnNewDocument;
property OnOpenDocument : TNotifyEvent read FOnOpenDocument write FOnOpenDocument;
property OnCloseDocument : TNotifyEvent read FOnCloseDocument write FOnCloseDocument;
property OnSaveDocument : TNotifyEvent read FOnSaveDocument write FOnSaveDocument;//添加
end;

TWordObject = class
private
FWordApp : _Application;
FEventSink : TWordEventSink;
function GetCaption : String;
procedure SetCaption(Value : String);
function GetVisible : Boolean;
procedure SetVisible(Value : Boolean);
function GetOnQuit : TNotifyEvent;
procedure SetOnQuit(Value : TNotifyEvent);
function GetOnDocumentChange : TNotifyEvent;
procedure SetOnDocumentChange(Value : TNotifyEvent);
function GetOnNewDocument: TNotifyEvent;
procedure SetOnNewDocument(Value : TNotifyEvent);
function GetOnOpenDocument: TNotifyEvent;
procedure SetOnOpenDocument(Value : TNotifyEvent);
function GetOnCloseDocument: TNotifyEvent;
procedure SetOnCloseDocument(Value : TNotifyEvent);
function GetOnSaveDocument: TNotifyEvent; //添加
procedure SetOnSaveDocument(Value : TNotifyEvent); //添加
public
constructor Create;
destructor Destroy; override;
procedure NewDoc(Template : String);
procedure CloseDoc;
procedure InsertText(Text : String);
procedure Print;
procedure SaveAs(Filename : String);
published
property Application : _Application read FWordApp;
property Caption : String read GetCaption write SetCaption;
property Visible : Boolean read GetVisible write SetVisible;
property OnQuit : TNotifyEvent read GetOnQuit write SetOnQuit;
property OnDocumentChange : TNotifyEvent read GetOnDocumentChange write SetOnDocumentChange;
property OnNewDocument : TNotifyEvent read GetOnNewDocument write SetOnNewDocument;
property OnOpenDocument : TNotifyEvent read GetOnOpenDocument write SetOnOpenDocument;
property OnCloseDocument : TNotifyEvent read GetOnCloseDocument write SetOnCloseDocument;
property OnSaveDocument : TNotifyEvent read GetOnSaveDocument write SetOnSaveDocument; //添加
end;

implementation

uses
ComObj, Variants;

{ TWordEventSink implementation }

constructor TWordEventSink.Create(AnOwner : TObject; AnAppDispatch: IDispatch; const AnAppDispIntfIID, ADocDispIntfIID: TGUID);
begin
inherited Create;

FOwner := AnOwner;
FAppDispIntfIID := AnAppDispIntfIID;
FDocDispIntfIID := ADocDispIntfIID;
FAppDispatch := AnAppDispatch;

// Hook the sink up to the automation server (Word97)
InterfaceConnect(FAppDispatch,FAppDispIntfIID,Self,FAppConnection);
end;

destructor TWordEventSink.Destroy;
begin
// Unhook the sink from the automation server (Word97)
InterfaceDisconnect(FAppDispatch,FAppDispIntfIID,FAppConnection);

inherited Destroy;
end;

function TWordEventSink.QueryInterface(const IID: TGUID; out Obj): HRESULT;
begin
// We need to return the two event interfaces when they're asked for
Result := E_NOINTERFACE;
if GetInterface(IID,Obj) then
Result := S_OK;
if IsEqualGUID(IID,FAppDispIntfIID) and GetInterface(IDispatch,Obj) then
Result := S_OK;
if IsEqualGUID(IID,FDocDispIntfIID) and GetInterface(IDispatch,Obj) then
Result := S_OK;
end;

function TWordEventSink._AddRef: Integer;
begin
// Skeleton implementation
Result := 2;
end;

function TWordEventSink._Release: Integer;
begin
// Skeleton implementation
Result := 1;
end;

function TWordEventSink.GetTypeInfoCount(out Count: Integer): HRESULT;
begin
// Skeleton implementation
Count := 0;
Result := S_OK;
end;

function TWordEventSink.GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HRESULT;
begin
// Skeleton implementation
Result := E_NOTIMPL;
end;

function TWordEventSink.GetIDsOfNames(const IID: TGUID; Names: Pointer;
NameCount, LocaleID: Integer; DispIDs: Pointer): HRESULT;
begin
// Skeleton implementation
Result := E_NOTIMPL;
end;

function TWordEventSink.Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HRESULT;
begin
// Fire the different event handlers when
// the different event methods are invoked
case DispID of
2 : if Assigned(FOnQuit) then
FOnQuit(FOwner);
3 : begin
if Assigned(FOnDocumentChange) then
FOnDocumentChange(FOwner);
// When we see a document change, we also need to disconnect the
// sink from the old document, and hook it up to the new document
InterfaceDisconnect(FDocDispatch,FDocDispIntfIID,FDocConnection);
try
FDocDispatch := _Application(FAppDispatch).ActiveDocument;
InterfaceConnect(FDocDispatch,FDocDispIntfIID,Self,FDocConnection);
except;
end;
end;
4 : if Assigned(FOnNewDocument) then
FOnNewDocument(FOwner);
5 : if Assigned(FOnOpenDocument) then
FOnOpenDocument(FOwner);
6 : if Assigned(FOnCloseDocument) then
FOnCloseDocument(FOwner);
8 : if Assigned(FOnSaveDocument) then
FOnSaveDocument(FOwner);
end;

Result := S_OK;
end;

{ TWordObject implementation }

constructor TWordObject.Create;
begin
// Fire off Word97 and create the event sink
FWordApp := CoWordApplication.Create;
FEventSink := TWordEventSink.Create(Self,FWordApp,ApplicationEvents,DocumentEvents);
end;

destructor TWordObject.Destroy;
var
SaveChanges,
OriginalFormat,
RouteDocument : OleVariant;
begin
SaveChanges := WdDoNotSaveChanges;
OriginalFormat := UnAssigned;
RouteDocument := UnAssigned;
try
FWordApp.Quit(SaveChanges,OriginalFormat,RouteDocument);
except
end;
FEventSink := nil;
inherited Destroy;
end;

function TWordObject.GetVisible : Boolean;
begin
Result := FWordApp.Visible;
end;

procedure TWordObject.SetCaption(Value : String);
begin
FWordApp.Caption := Value;
end;

function TWordObject.GetCaption : String;
begin
Result := FWordApp.Caption;
end;

procedure TWordObject.SetVisible(Value : Boolean);
begin
FWordApp.Visible := Value;
end;

function TWordObject.GetOnQuit : TNotifyEvent;
begin
Result := FEventSink.OnQuit;
end;

procedure TWordObject.SetOnQuit(Value : TNotifyEvent);
begin
FEventSink.OnQuit := Value;
end;

function TWordObject.GetOnDocumentChange : TNotifyEvent;
begin
Result := FEventSink.OnDocumentChange;
end;

procedure TWordObject.SetOnDocumentChange(Value : TNotifyEvent);
begin
FEventSink.OnDocumentChange := Value;
end;

function TWordObject.GetOnNewDocument : TNotifyEvent;
begin
Result := FEventSink.OnNewDocument;
end;

procedure TWordObject.SetOnNewDocument(Value : TNotifyEvent);
begin
FEventSink.OnNewDocument := Value;
end;

function TWordObject.GetOnOpenDocument : TNotifyEvent;
begin
Result := FEventSink.OnOpenDocument;
end;

procedure TWordObject.SetOnOpenDocument(Value : TNotifyEvent);
begin
FEventSink.OnOpenDocument := Value;
end;

function TWordObject.GetOnCloseDocument : TNotifyEvent;
begin
Result := FEventSink.OnCloseDocument;
end;

function TWordObject.GetOnSaveDocument : TNotifyEvent; //添加
begin
Result := FEventSink.OnSaveDocument;
end;

procedure TWordObject.SetOnCloseDocument(Value : TNotifyEvent);
begin
FEventSink.OnCloseDocument := Value;
end;

procedure TWordObject.SetOnSaveDocument(Value : TNotifyEvent); //添加
begin
FEventSink.OnSaveDocument := Value;
end;

procedure TWordObject.InsertText(Text : String);
begin
FWordApp.Selection.TypeText(Text);
end;

procedure TWordObject.NewDoc(Template : String);
var
DocTemplate,
NewTemplate : OleVariant;
begin
DocTemplate := Template;
NewTemplate := False;
FWordApp.Documents.Add(DocTemplate,NewTemplate);
end;

procedure TWordObject.CloseDoc;
var
SaveChanges,
OriginalFormat,
RouteDocument : OleVariant;
begin
SaveChanges := WdDoNotSaveChanges;
OriginalFormat := UnAssigned;
RouteDocument := UnAssigned;
FWordApp.ActiveDocument.Close(SaveChanges,OriginalFormat,RouteDocument);
end;

procedure TWordObject.Print;
begin
OleVariant(FWordApp).PrintOut;
end;

procedure TWordObject.SaveAs(Filename : String);
begin
OleVariant(FWordApp).ActiveDocument.SaveAs(FileName);
end;

end.
 
哦,荷塘新月,其实思路是有的。不过暂时没有看到具体公开的实现:)
以下为俺那个巨长的帖子里面摘出来的。当初我实现的时候因为使用了VBA,所以直接在Word中实现了(那个比较简单),但是下面这个实现方式很好。也属于真正的“正路”[:D]

来自:DragonPC_???, 时间:2001-12-1 21:44:00, ID:758037
写的不错,但是我想说一些不同的话,

CreateOLEObject创建的variant类型变量,运行期才通过IDispatch接口进行方法调用,所以没有Code Insight,
开发效率、运行效率都要差一点。(IDispatch接口是为适合Automation技术开发的,比COM更高级,更抽象)

http://www.delphibbs.com/delphibbs/dispq.asp?lid=680785
http://www.delphibbs.com/delphibbs/dispq.asp?lid=420919

Delphi Servers 组件和Import Library是一回事来着,使用Import Library会更加通用一点,除了Word,
其它的支持Automation的应用程序都可以使用,比如Autocad、IE等等。但是Import Library有很多的bug,
经常出错。这一点玩过COM编程的人都知道,但我还是推荐使用这套技术进行COM或者Automation工作,效
率高的多。hubdog是这方面的专家,你们可以等他来介绍介绍。

最后我推荐Binh Ly的站点,他是Borland的COM专家,如果经常逛Borland的Automation新闻组,你肯定认
识他,站点有很多介绍和工具下载,大家可以自己看看。Delphi 4编程技术内幕的作者Chris Clvert也是
个中好手,他的站点资料多多。

http://www.techvanguards.com/
http://www.delphibbs.com/delphibbs/dispq.asp?lid=738352



来自:SeaHawk, 时间:2002-1-27 21:24:00, ID:888705
公布我的研究结果,有不正确的地方请指正:
要调用Office里面的按钮事件,实际上是需要连接到按钮事件的IDispatch接口。按钮接口
的定义在Office2000.pas文件中。要连接到这些接口,你须自己编写Invoke方法。但是有些难
度,我曾经试了一下,但是不成功。但是今天在http://www.techvanguards.com/看到有一个软
件叫eventsinkimp,可以自动生成连接Com事件的组件,立马下载了一个(现在是2.0版)。
安装完了运行,发现可以Import Type Library,和Delphi一样,但是下面可以选择跟踪
那一个COM的事件。于是选择:MicroSoft Office Object Library9.0,然后选择一个相应的
接口。生成三个文件:Office_TLB,OfficeEvents和Office_TLB.dcr。
然后回到delphi,Install Component,在ACTIVEX里面出现了几个控件:
TOfficeCommandBarButtonEvents等,这就是我们想要的!!!里面有click事件。
接下来就简单了,先建立一个Bar然后建立一个Commandbarbutton,然后调用
TOfficeCommandBarButtonEvents.connect方法把我们刚才建立的Commandbarbutton
连接起来,这样就可以了!!!
注意:安装了windows installer 2.0的同志恐怕麻烦一点,安装不上去,害得我
重装了系统,哪位解决了的通知我一声。这是我为了安装XML4.0装的,没办法。
Ably:给分!!:)
 
to zhihuali:你的改法和我改的一样!谢谢!

to yzhshi:刚才正在看这段文章,正想把它拿到这里来,没想到你已经把它拿来了!谢谢!
 
这个问题嘛,参照Delphi自带的demo啦,里面就有啦。嘿嘿这个demo我看过几遍呢。
 
用TWordApplication组件就行了,它已经解决了所有你要解决的问题,
Word是一个自动化服务器,在Word97时只支持三个事件,即OnNewDocument、
OnOpenDocument、OnCloseDocument。所以在Delphi的那个Demo中只实现了这几个事件。
但在Word2000中又新增了几个事件,如OnSaveDocument。
如果自动化服务器不支持这个事件,客户端无论怎么编写都是没用。只有自动化服务器
支持特定的事件,才可以在客户端编写一个EventSink,即事件接收器,把这个EventSink用
InterfaceConnect函数向自动化服务器注册,自动化服务器在触发特定的事件时便会调这个
事件接收器。
 
我有一个问题,希望大家能讨论一下,那就有关OleContainer组件菜单合并的问题,
合并时文件一栏的菜单全看不见了,不知道有什么办法能够控件这个菜单合并,我查看了
ole/automation版的所有文件都没看到具体的解决方案。希望各位大虾能想想办法。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
后退
顶部