There are 2 ways that event sinking can be performed on Word:
To use the IAdviseSink interface you must first write an object that implements this standard interface. This object is then passed to the DAdvise method of a Word Document's IDataObject interface or to the Advise method of a Word Document's IOleObject interface. Refer to the help MS help on IAdviseSink for more information on this interface.
Word provides the following event sources that can be sinked to:
ApplicationEvents:
procedure Startup; dispid 1;
procedure Quit; dispid 2;
procedure DocumentChange; dispid 3;procedure New; dispid 4;
procedure Open; dispid 5;
procedure Close; dispid 6;procedure GotFocus; dispid -2147417888;
procedure LostFocus; dispid -2147417887;There appears to be some limitations with Word's implementation of connection points. When a document is closed in Word, without closing Word itself, Word sends a DocumentEvents.Close message and then an
ApplicationEvents.DocumentChange message. Then when Word is closed nothing is sent. On the other hand if Word is closed with an open document then it sends a DocumentEvents.Close message and an
ApplicationEvents.Quit message. Another problem is that Word will send the DocumentEvents.Close message when the user "closes" the document but before the "Do you wish to save changes?" dialog is shown. So if the user then selects cancel the document is never closed but the DocumentEvents.Close
message was sent.
Sample Code (StartingConnection)
uses
Word_TLB, activex, comobj, ConnectionObject
// ConnectionObject is the unit containing TWordConnection
procedure StartWordConnection(WordApp: _Application;
WordDoc: _Document;
var WordSink: TWordConnection);
var
PointContainer: IConnectionPointContainer;
Point: IConnectionPoint;
begin
try
{ TWordConnection is the COM object which receives the
notifications from Word. Make sure to free WordSink when
you are done with it. }
WordSink := TWordConnection.Create;
WordSink.WordApp := WordApp;
WordSink.WordDoc := WordDoc;
// Sink with a Word application
OleCheck(WordApp.QueryInterface(IConnectionPointContainer, PointContainer));
if Assigned(PointContainer) then
begin
OleCheck(PointContainer.FindConnectionPoint(ApplicationEvents, Point));
if Assigned(Point) then
Point.Advise((WordSink as IUnknown), WordSink.AppCookie);
end;
// Sink with a Word document
OleCheck(WordDoc.QueryInterface(IConnectionPointContainer, PointContainer));
if Assigned(PointContainer) then
begin
OleCheck(PointContainer.FindConnectionPoint(DocumentEvents, Point));
if Assigned(Point) then
Point.Advise((WordSink as IUnknown), WordSink.DocCookie);
end;
except
on E: Exception do
ShowMessage(E.Message);
end;
end;unit ConnectionObject;
interface
uses
Word_TLB;
type
TWordConnection = class(TObject, IUnknown, IDispatch)
protected
{ IUnknown }
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
{ IDispatch }
function GetIDsOfNames(const IID: TGUID; Names: Pointer;
NameCount, LocaleID: Integer;
DispIDs: Pointer): HResult; stdcall;
function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
Flags: Word; var Params;
VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
public
WordApp: _Application;
WordDoc: _Document;
AppCookie, DocCookie: Integer;
end;
implementation
uses
Windows, ActiveX, Main;
procedure LogComment(comment: String);
begin
Form1.Memo1.Lines.Add(comment);
end;
{ IUnknown Methods }
function TWordConnection._AddRef: Integer;
begin
Result := 2;
end;
function TWordConnection._Release: Integer;
begin
Result := 1;
end;
function TWordConnection.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
Result := E_NOINTERFACE;
Pointer(Obj) := nil;
if GetInterface (IID, Obj) then
Result := S_OK;
if (not Succeeded(Result)) then
if IsEqualIID(IID, DocumentEvents) or IsEqualIID(IID, ApplicationEvents) then
if GetInterface(IDispatch, Obj) then
Result := S_OK;
end;
{ IDispatch Methods }
function TWordConnection.GetIDsOfNames(const IID: TGUID; Names: Pointer;
NameCount, LocaleID: Integer;
DispIDs: Pointer): HResult;
begin
Result := E_NOTIMPL;
end;
function TWordConnection.GetTypeInfo(Index, LocaleID: Integer;
out TypeInfo): HResult;
begin
Pointer(TypeInfo) := nil;
Result := E_NOTIMPL;
end;
function TWordConnection.GetTypeInfoCount(out Count: Integer): HResult;
begin
Count := 0;
Result := E_NOTIMPL;
end;
function TWordConnection.Invoke(DispID: Integer; const IID: TGUID;
LocaleID: Integer; Flags: Word;
var Params; VarResult, ExcepInfo,
ArgErr: Pointer): HResult;
begin
// This is the entry point for Word event sinking
Result := S_OK;
case DispID of
1: ; // Startup
2: ; // Quit
3: ; // Document change
4: ; // New document
5: ; // Open document
6: ; // Close document
else
Result := E_INVALIDARG;
end;
end;
end.