function TIEEvents._Release: Integer; begin // Always maintain 1 ref count (component holds the ref count) result := 1; end;
function TIEEvents.QueryInterface(const IID: TGUID; out Obj): HResult; begin // Clear interface pointer Pointer(Obj) := nil;
// Attempt to get the requested interface if (GetInterface(IID, Obj)) then // Success result := S_OK // Check to see if the guid requested is for the event else if (IsEqualIID(IID, FSinkIID)) then
begin // Event is dispatch based, so get dispatch interface (closest we can come) if (GetInterface(IDispatch, Obj)) then // Success result := S_OK else // Failure result := E_NOINTERFACE; end
else // Failure result := E_NOINTERFACE; end;
function TIEEvents.GetIDsOfNames(const IID: TGUID; Names: Pointer; NameCount,
LocaleID: Integer; DispIDs: Pointer): HResult; begin // Not implemented result := E_NOTIMPL; end;
function TIEEvents.GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; begin // Clear the result interface Pointer(TypeInfo) := nil; // No type info for our interface result := E_NOTIMPL; end;
function TIEEvents.GetTypeInfoCount(out Count: Integer): HResult; begin // Zero type info counts Count := 0; // Return success result := S_OK; end;
function TIEEvents.Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; var pdpParams: PDispParams;
lpDispIDs: array[0..63] of TDispID;
dwCount: Integer; begin
// Get the parameters pdpParams := @Params;
// Events can only be called with method dispatch, not property get/set if ((Flags and DISPATCH_METHOD) > 0) then
begin // Clear DispID list ZeroMemory(@lpDispIDs, SizeOf(lpDispIDs)); // Build dispatch ID list to handle named args if (pdpParams^.cArgs > 0) then
begin // Reverse the order of the params because they are backwards for dwCount := 0 to Pred(pdpParams^.cArgs) do lpDispIDs[dwCount] := Pred(pdpParams^.cArgs) - dwCount; // Handle named arguments if (pdpParams^.cNamedArgs > 0) then
begin
for dwCount := 0 to Pred(pdpParams^.cNamedArgs) do lpDispIDs[pdpParams^.rgdispidNamedArgs^[dwCount]] := dwCount; end; end; // Unless the event falls into the "else" clause of the case statement the result is S_OK result := S_OK; // Handle the event case DispID of 102: DoStatusTextChange(pdpParams^.rgvarg^[lpDispIds[0]].bstrval);
104: DoDownloadComplete;
105: DoCommandStateChange(pdpParams^.rgvarg^[lpDispIds[0]].lval,
pdpParams^.rgvarg^[lpDispIds[1]].vbool);
106: DoDownloadBegin;
108: DoProgressChange(pdpParams^.rgvarg^[lpDispIds[0]].lval,
pdpParams^.rgvarg^[lpDispIds[1]].lval);
112: DoPropertyChange(pdpParams^.rgvarg^[lpDispIds[0]].bstrval);
113: DoTitleChange(pdpParams^.rgvarg^[lpDispIds[0]].bstrval);
250: DoBeforeNavigate2(IDispatch(pdpParams^.rgvarg^[lpDispIds[0]].dispval),
POleVariant(pdpParams^.rgvarg^[lpDispIds[1]].pvarval)^,
POleVariant(pdpParams^.rgvarg^[lpDispIds[2]].pvarval)^,
POleVariant(pdpParams^.rgvarg^[lpDispIds[3]].pvarval)^,
POleVariant(pdpParams^.rgvarg^[lpDispIds[4]].pvarval)^,
POleVariant(pdpParams^.rgvarg^[lpDispIds[5]].pvarval)^,
pdpParams^.rgvarg^[lpDispIds[6]].pbool^);
251: DoNewWindow2(IDispatch(pdpParams^.rgvarg^[lpDispIds[0]].pdispval^),
pdpParams^.rgvarg^[lpDispIds[1]].pbool^);
252: DoNavigateComplete2(IDispatch(pdpParams^.rgvarg^[lpDispIds[0]].dispval),
POleVariant(pdpParams^.rgvarg^[lpDispIds[1]].pvarval)^);
253: begin // Special case handler. When Quit is called, IE is going away so we might
// as well unbind from the interface by calling disconnect. DoOnQuit; // Call disconnect Disconnect; end;
254: DoOnVisible(pdpParams^.rgvarg^[lpDispIds[0]].vbool);
255: DoOnToolBar(pdpParams^.rgvarg^[lpDispIds[0]].vbool);
256: DoOnMenuBar(pdpParams^.rgvarg^[lpDispIds[0]].vbool);
257: DoOnStatusBar(pdpParams^.rgvarg^[lpDispIds[0]].vbool);
258: DoOnFullScreen(pdpParams^.rgvarg^[lpDispIds[0]].vbool);
259: DoDocumentComplete(IDispatch(pdpParams^.rgvarg^[lpDispIds[0]].dispval),
POleVariant(pdpParams^.rgvarg^[lpDispIds[1]].pvarval)^);
260: DoOnTheaterMode(pdpParams^.rgvarg^[lpDispIds[0]].vbool); else // Have to idea of what event they are calling result := DISP_E_MEMBERNOTFOUND; end; end
else // Called with wrong flags result := DISP_E_MEMBERNOTFOUND; end;
constructor TIEEvents.Create(AOwner: TComponent); begin // Perform inherited inherited Create(AOwner);
// Set the event sink IID FSinkIID := DWebBrowserEvents2; end;
procedure TIEEvents.ConnectTo(Source: IWebBrowser2); var pvCPC: IConnectionPointContainer; begin // Disconnect from any currently connected event sink Disconnect; // Query for the connection point container and desired connection point.
// On success, sink the connection point OleCheck(Source.QueryInterface(IConnectionPointContainer, pvCPC));
OleCheck(pvCPC.FindConnectionPoint(FSinkIID, FCP));
OleCheck(FCP.Advise(Self, FCookie)); // Update internal state variables FSource := Source; // We are in a connected state FConnected := True; // Release the temp interface pvCPC := nil; end;
procedure TIEEvents.Disconnect; begin // Do we have the IWebBrowser2 interface? if Assigned(FSource) then
begin
try // Unadvise the connection point OleCheck(FCP.Unadvise(FCookie)); // Release the interfaces FCP := nil;
FSource := nil; except Pointer(FCP) := nil;
Pointer(FSource) := nil; end; end;
// Disconnected state FConnected := False; end;
procedure TIEEvents.DoStatusTextChange(const Text: WideString); begin // Call assigned event if Assigned(FStatusTextChange) then FStatusTextChange(Self, Text); end;
procedure TIEEvents.DoProgressChange(Progress: Integer; ProgressMax: Integer); begin // Call assigned event if Assigned(FProgressChange) then FProgressChange(Self, Progress, ProgressMax); end;
procedure TIEEvents.DoCommandStateChange(Command: Integer; Enable: WordBool); begin // Call assigned event if Assigned(FCommandStateChange) then FCommandStateChange(Self, Command, Enable); end;
procedure TIEEvents.DoDownloadBegin; begin // Call assigned event if Assigned(FDownloadBegin) then FDownloadBegin(Self); end;
procedure TIEEvents.DoDownloadComplete; begin // Call assigned event if Assigned(FDownloadComplete) then FDownloadComplete(Self); end;
procedure TIEEvents.DoTitleChange(const Text: WideString); begin // Call assigned event if Assigned(FTitleChange) then FTitleChange(Self, Text); end;
procedure TIEEvents.DoPropertyChange(const szProperty: WideString); begin // Call assigned event if Assigned(FPropertyChange) then FPropertyChange(Self, szProperty); end;
procedure TIEEvents.DoBeforeNavigate2(const pDisp: IDispatch; var URL: OleVariant; var Flags:
OleVariant; var TargetFrameName: OleVariant; var PostData: OleVariant; var Headers: OleVariant; var Cancel: WordBool); begin // Call assigned event if Assigned(FBeforeNavigate2) then FBeforeNavigate2(Self, pDisp, URL, Flags, TargetFrameName, PostData, Headers, Cancel); end;
procedure TIEEvents.DoNewWindow2(var ppDisp: IDispatch; var Cancel: WordBool); var pvDisp: IDispatch; begin // Call assigned event if Assigned(FNewWindow2) then
begin
if Assigned(ppDisp) then pvDisp := ppDisp else pvDisp := nil;
FNewWindow2(Self, pvDisp, Cancel);
ppDisp := pvDisp; end; end;
procedure TIEEvents.DoNavigateComplete2(const pDisp: IDispatch; var URL: OleVariant); begin // Call assigned event if Assigned(FNavigateComplete2) then FNavigateComplete2(Self, pDisp, URL); end;
procedure TIEEvents.DoDocumentComplete(const pDisp: IDispatch; var URL: OleVariant); begin // Call assigned event if Assigned(FDocumentComplete) then FDocumentComplete(Self, pDisp, URL); end;
procedure TIEEvents.DoOnQuit; begin // Call assigned event if Assigned(FOnQuit) then FOnQuit(Self); end;
procedure TIEEvents.DoOnVisible(Visible: WordBool); begin // Call assigned event if Assigned(FOnVisible) then FOnVisible(Self, Visible); end;
procedure TIEEvents.DoOnToolBar(ToolBar: WordBool); begin // Call assigned event if Assigned(FOnToolBar) then FOnToolBar(Self, ToolBar); end;
procedure TIEEvents.DoOnMenuBar(MenuBar: WordBool); begin // Call assigned event if Assigned(FOnMenuBar) then FOnMenuBar(Self, MenuBar); end;
procedure TIEEvents.DoOnStatusBar(StatusBar: WordBool); begin // Call assigned event if Assigned(FOnStatusBar) then FOnStatusBar(Self, StatusBar); end;
procedure TIEEvents.DoOnFullScreen(FullScreen: WordBool); begin // Call assigned event if Assigned(FOnFullScreen) then FOnFullScreen(Self, FullScreen); end;
procedure TIEEvents.DoOnTheaterMode(TheaterMode: WordBool); begin // Call assigned event if Assigned(FOnTheaterMode) then FOnTheaterMode(Self, TheaterMode); end;
procedure Register; begin // Register the component on the Internet tab of the IDE RegisterComponents('Internet', [TIEEvents]); end;
end.
--- Project source ---- //Notes: Add a button and the IEEvents component to Form1. The button1 click event
// shows how the IE enumeration is achieved, and shows how the binding is done:
procedure TForm1.Button1Click(Sender: TObject); var pvShell: IShellWindows;
pvWeb2: IWebBrowser2;
ovIE: OleVariant;
dwCount: Integer; begin // Create the shell windows interface pvShell := CoShellWindows.Create; // Walk the internet explorer windows for dwCount := 0 to Pred(pvShell.Count) do
begin // Get the interface ovIE := pvShell.Item(dwCount); // At this point you can evaluate the interface (LocationUrl, etc)
// to decide if this is the one you want to connect to. For demo purposes,
// the code will bind to the first one ShowMessage(ovIE.LocationURL); // QI for the IWebBrowser2 if (IDispatch(ovIE).QueryInterface(IWebBrowser2, pvWeb2) = S_OK) then
begin IEEvents1.ConnectTo(pvWeb2); // Release the interface pvWeb2 := nil; end; // Clear the variant ovIE := Unassigned; // Break if we connected if IEEvents1.Connected then break; end; // Release the shell windows interface pvShell := nil; end;
procedure TForm1.FormCreate(Sender: TObject); begin // Create the time list FTimeList := TList.Create; end;
procedure TForm1.FormDestroy(Sender: TObject); begin // Free the time list FTimeList.Free; end;
procedure TForm1.IEEvents1DownloadBegin(Sender: TObject); begin // Add the current time to the list FTimeList.Add(Pointer(GetTickCount)); end;
procedure TForm1.IEEvents1DownloadComplete(Sender: TObject); var dwTime: LongWord; begin // Pull the top item off the list (make sure there is one) if (FTimeList.Count > 0) then
begin dwTime := LongWord(FTimeList[Pred(FTimeList.Count)]);
FTimeList.Delete(Pred(FTimeList.Count)); // Now calculate total based on current time dwTime := GetTickCount - dwTime; // Display a message showing total download time ShowMessage(Format('Download time for "%s" was %d ms', [IEEvents1.WebObj.LocationURL, dwTime])); end; end;
procedure TForm1.IEEvents1Quit(Sender: TObject); begin ShowMessage('About to disconnect'); end;