我正在使用Delphi 2007.我可以成功地使用WebBrowser.Navigate發佈數據到網站,但之後,當該網站返回PDF時,它出現在屏幕上的瀏覽器,我無法弄清楚如何以編程方式獲取PDF。我可以使用Document.Body.InnerHTML看到一些文本和HTML,但不能看到PDF。有人可以演示如何獲取POST後出現的PDF?在使用TWebBrowser發佈到網站後獲取PDF返回
感謝yoU!
我正在使用Delphi 2007.我可以成功地使用WebBrowser.Navigate發佈數據到網站,但之後,當該網站返回PDF時,它出現在屏幕上的瀏覽器,我無法弄清楚如何以編程方式獲取PDF。我可以使用Document.Body.InnerHTML看到一些文本和HTML,但不能看到PDF。有人可以演示如何獲取POST後出現的PDF?在使用TWebBrowser發佈到網站後獲取PDF返回
感謝yoU!
您可以使用IE4 +選項來使用您自己的協議捕獲所有互聯網流量。您甚至可以掛接協議http(IIRC),並且在需要加載數據時使用WIndows函數和/或Indy組件。
這是一個單元,這樣做:
{
This component allows you to dynamically create your own internet protocols for
Microsoft Internet Explorer 4+. Simply place the component on your form, set the protocol
property to something useful and set the Active property.
For example, when the Protocol is set to 'private', you can trap requests to
'private:anythingyoulike'.
}
unit UnitInternetProtocol;
// Developed by: R.A. Hornstra
// (C) 2001 ContinuIT BV
interface
uses
SysUtils, Windows, Classes, Messages;
type
TInternetProtocol = class;
{
When a request is made, the data must be returned in a TStream descendant.
The request is present in Request. The result should be saved in Stream.
When no data can be linked to the request, leave Stream equal to nil.
See @link(TInternetProtocol.OnRequestStream) and @link(TInternetProtocol.OnReleaseStream).
}
TProtocolRequest = procedure(Sender: TInternetProtocol; const Request: string;
var Stream: TStream) of object;
{
When a request is done by the Microsoft Internet Explorer it is done via an URL.
This URL starts with a protocol, than a colon and than a protocol specific resource identifier.
New protocols can be added dynamically and privately for each session.
This component will register/deregister new protocols to the Microsoft Internet Explorer.
You should set the name of the protocol with @link(Protocol), activate/deactivate the
protocol with @link(Active). The implementation of the protocol can be done with the
events @link(OnRequestStream) and @link(OnReleaseStream).
}
TInternetProtocol = class(TComponent)
private
FHandle: HWnd;
FActive: Boolean;
FProtocol: string;
FRequest: TProtocolRequest;
FRelease: TProtocolRequest;
procedure SetActive(const Value: Boolean);
procedure SetProtocol(const Value: string);
protected
procedure Loaded; override;
procedure Activate;
procedure Deactivate;
procedure WndProc(var Message: TMessage);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
{
Setting this property will activate or deactivate the internet
}
property Active: Boolean read FActive write SetActive;
{
The protocol name must be specified. default, this is 'private'.
You should fill it here without the trailing colon (that's part of the URL notation).
Protocol names should be valid identifiers.
}
property Protocol: string read FProtocol write SetProtocol;
{
When a request is made on the selected protocol, this event is fired.
It should return a TStream, based upon the given Request.
The default behaviour of TInternetProtocol is freeing the stream.
To override or monitor this behaviour, use @link(OnRequestStream).
}
property OnRequestStream: TProtocolRequest read FRequest write FRequest;
{
When a stream is about to be released by TInternetProtocol, you can override the
default behaviour. By Setting the Stream variable to nil in the OnReleaseStream handler,
the stream will not be released by TInternetProtocol.
This is handy when you're implementing a caching system, or for some reason need control on
the creation and deletion to the streams.
The default behaviour of TInternetProtocol is freeing the stream.
}
property OnReleaseStream: TProtocolRequest read FRelease write FRelease;
end;
{
All exceptions raised by @link(TInternetProtocol) are of type EInternetException.
}
EInternetException = class(Exception);
procedure Register;
implementation
uses
ComObj, ActiveX, UrlMon, Forms;
resourcestring
strNotAValidProtocol = 'The Internet Protocol selected is not a valid protocol identifier';
// todo: move registration to separate file
procedure Register;
begin
Classes.RegisterComponents('Internet',[TInternetProtocol]);
end;
// forward declarations
procedure RegisterProtocol(Protocol: string; Handler: TInternetProtocol); forward;
procedure UnregisterProtocol(Protocol: string); forward;
const
IID_TInternetProtocolHandler: TGUID = '{B74826E0-1107-11D5-B166-0010D7090486}';
WM_STREAMNEEDED = WM_USER;
{ TInternetProtocol }
constructor TInternetProtocol.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FActive := False;
FProtocol := 'private';
FRequest := nil;
FRelease := nil;
FHandle := Forms.AllocateHWnd(WndProc);
end;
destructor TInternetProtocol.Destroy;
begin
Active := False;
Forms.DeallocateHWnd(FHandle);
inherited Destroy;
end;
procedure TInternetProtocol.Loaded;
begin
inherited Loaded;
if FActive then Activate;
end;
procedure TInternetProtocol.SetActive(const Value: Boolean);
begin
if Value = FActive then Exit;
if Value then begin
if not (csLoading in ComponentState) then Activate;
end else begin
Deactivate;
end;
FActive := Value;
end;
procedure TInternetProtocol.Activate;
begin
if csDesigning in ComponentState then Exit;
RegisterProtocol(FProtocol,Self);
end;
procedure TInternetProtocol.Deactivate;
begin
if csDesigning in ComponentState then Exit;
UnregisterProtocol(FProtocol);
end;
procedure TInternetProtocol.SetProtocol(const Value: string);
var AActive: Boolean;
begin
if not SysUtils.IsValidIdent(Value) then raise EInternetException.Create(strNotAValidProtocol);
AActive := FActive;
try
Active := False;
FProtocol := Value;
finally
Active := AActive;
end;
end;
procedure TInternetProtocol.WndProc(var Message: TMessage);
var
Msg: packed record
Msg: Longword;
Request: PChar;
Stream: ^TStream;
end;
begin
if Message.Msg = WM_STREAMNEEDED then begin
System.Move(Message,Msg,SizeOf(Msg));
if Assigned(FRequest) then FRequest(Self,string(Msg.Request),Msg.Stream^);
end else Message.Result := Windows.DefWindowProc(FHandle,Message.Msg,Message.WParam,Message.LParam);
end;
var
Session: IInternetSession; // The current Internet Session
Factory: IClassFactory; // Factory of our IInternetProtocol implementation
Lock: TRTLCriticalSection; // The lock for thread safety
List: TStrings; // The list of active protocol handlers
type
TInternetProtocolHandler = class(TInterfacedObject, IInternetProtocol)
private
ProtSink: IInternetProtocolSink; // Protocol Sink that needs the data
Stream: TStream; // Stream containing the data
StreamPosition: Integer; // Current Position in the stream
StreamSize: Integer; // Current size of the stream
LockCount: Integer; // Lock count for releasing data
procedure ReleaseStream;
public
{ IInternetProtocol }
function Start(szUrl: PWideChar; OIProtSink: IInternetProtocolSink;
OIBindInfo: IInternetBindInfo; grfPI, dwReserved: DWORD): HResult; stdcall;
function Continue(const ProtocolData: TProtocolData): HResult; stdcall;
function Abort(hrReason: HResult; dwOptions: DWORD): HResult; stdcall;
function Terminate(dwOptions: DWORD): HResult; stdcall;
function Suspend: HResult; stdcall;
function Resume: HResult; stdcall;
function Read(pv: Pointer; cb: ULONG; out cbRead: ULONG): HResult; stdcall;
function Seek(dlibMove: LARGE_INTEGER; dwOrigin: DWORD;
out libNewPosition: ULARGE_INTEGER): HResult; stdcall;
function LockRequest(dwOptions: DWORD): HResult; stdcall;
function UnlockRequest: HResult; stdcall;
end;
TInternetProtocolHandlerFactory = class(TInterfacedObject, IClassFactory)
public
{ IClassFactory }
function CreateInstance(const unkOuter: IUnknown; const iid: TIID; out obj): HResult; stdcall;
function LockServer(fLock: BOOL): HResult; stdcall;
end;
procedure RegisterProtocol(Protocol: string; Handler: TInternetProtocol);
var
i: Integer;
Proto: WideString;
begin
Windows.EnterCriticalSection(Lock);
try
// if we have a previous handler, delete that from the list.
i := List.IndexOf(Protocol);
if i >=0 then TInternetProtocol(List.Objects[i]).Active := False;
// If this is the first time, create the Factory and get the Internet Session object
if List.Count = 0 then begin
Factory := TInternetProtocolHandlerFactory.Create;
CoInternetGetSession(0, Session, 0);
end;
// Append ourselves to the list
List.AddObject(Protocol,Handler);
// Register the protocol with the Internet session
Proto := Protocol;
Session.RegisterNameSpace(Factory, IInternetProtocol{ IID_TInternetProtocolHandler}, PWideChar(Proto), 0, nil, 0);
finally
Windows.LeaveCriticalSection(Lock);
end;
end;
procedure UnregisterProtocol(Protocol: string);
var i: Integer;
Proto: WideString;
begin
Windows.EnterCriticalSection(Lock);
try
i := List.IndexOf(Protocol);
if i < 0 then Exit; // oops, protocol was somehow already freed... this should not happen
// unregister our namespace handler
Proto := Protocol; // to widestring
Session.UnregisterNameSpace(Factory, PWideChar(Proto));
// and free from list
List.Delete(i);
// see if we need to cleanup?
if List.Count = 0 then begin
// release the COM server
Session := nil;
Factory := nil;
end;
finally
Windows.LeaveCriticalSection(Lock);
end;
end;
{ TInternetProtocolHandler }
function TInternetProtocolHandler.Abort(hrReason: HResult; dwOptions: DWORD): HResult;
begin
Result := E_NOTIMPL;
end;
function TInternetProtocolHandler.Continue(const ProtocolData: TProtocolData): HResult;
begin
Result := S_OK;
end;
function TInternetProtocolHandler.LockRequest(dwOptions: DWORD): HResult;
begin
Inc(LockCount);
Result := S_OK;
end;
function TInternetProtocolHandler.Read(pv: Pointer; cb: ULONG; out cbRead: ULONG): HResult;
const Results: array [Boolean] of Longword = (E_PENDING, S_FALSE);
begin
if Assigned(Stream) then cbRead := Stream.Read(pv^,cb) else cbRead := 0;
Inc(StreamPosition, cbread);
Result := Results[StreamPosition = StreamSize];
end;
procedure TInternetProtocolHandler.ReleaseStream;
begin
// see if we can release the Stream...
if Assigned(Stream) then FreeAndNil(Stream);
Protsink := nil;
end;
function TInternetProtocolHandler.Resume: HResult;
begin
Result := E_NOTIMPL;
end;
function TInternetProtocolHandler.Seek(dlibMove: LARGE_INTEGER;
dwOrigin: DWORD; out libNewPosition: ULARGE_INTEGER): HResult;
begin
Result := E_NOTIMPL;
end;
function TInternetProtocolHandler.Start(szUrl: PWideChar; OIProtSink: IInternetProtocolSink;
OIBindInfo: IInternetBindInfo; grfPI,dwReserved: DWORD): HResult;
var URL, Proto: string;
i: Integer;
Handler: TInternetProtocol;
begin
// Sanity check.
Assert(Assigned(OIProtSink));
Assert(Assigned(szUrl));
Assert(Assigned(OIBindInfo));
URL := szUrl;
Stream := nil; // just to make sure...
// Clip the protocol name from the URL & change the URL to the proto specific part
i := Pos(':',URL);
if i > 0 then begin
Proto := Copy(URL,1,i-1);
URL := Copy(URL,i+1,MaxInt);
end;
Windows.EnterCriticalSection(Lock);
try
i := List.IndexOf(Proto);
if i >= 0 then begin
// we've found our protocol
Handler := TInternetProtocol(List.Objects[i]);
// And query. Use a Windows message for thread synchronization
Windows.SendMessage(Handler.FHandle,WM_STREAMNEEDED,WParam(PChar(URL)),LParam(@Stream));
end;
finally
Windows.LeaveCriticalSection(Lock);
end;
if not Assigned(Stream) then begin
Result := INET_E_USE_DEFAULT_PROTOCOLHANDLER;
Exit;
end;
// Setup all data
StreamSize := Stream.Size;
Stream.Position := 0;
StreamPosition := 0;
LockCount := 1;
// Get the protocol sink & start the 'downloading' process
ProtSink := OIProtSink;
ProtSink.ReportData(BSCF_FIRSTDATANOTIFICATION or BSCF_LASTDATANOTIFICATION or
BSCF_DATAFULLYAVAILABLE, StreamSize, StreamSize);
ProtSink.ReportResult(S_OK, S_OK, nil);
Result := S_OK;
end;
function TInternetProtocolHandler.Suspend: HResult;
begin
Result := E_NOTIMPL;
end;
function TInternetProtocolHandler.Terminate(dwOptions: DWORD): HResult;
begin
Dec(LockCount);
if LockCount = 0 then ReleaseStream;
Result := S_OK;
end;
function TInternetProtocolHandler.UnlockRequest: HResult;
begin
Dec(LockCount);
if LockCount = 0 then ReleaseStream;
Result := S_OK;
end;
{ TInternetProtocolHandlerFactory }
function TInternetProtocolHandlerFactory.CreateInstance(const unkOuter: IInterface;
const iid: TIID; out obj): HResult;
begin
if IsEqualGUID(iid, IInternetProtocol) then begin
IInternetProtocol(obj) := TInternetProtocolHandler.Create as IInternetProtocol;
Result := S_OK;
end else if IsEqualGUID(iid, IInterface) then begin
IInterface(obj) := TInternetProtocolHandler.Create as IInterface;
Result := S_OK;
end else begin
Result := E_NOINTERFACE;
end;
end;
function TInternetProtocolHandlerFactory.LockServer(fLock: BOOL): HResult;
begin
if fLock then _AddRef else _Release;
Result := S_OK;
end;
initialization
begin
// Get a critical section for thread synchro
Windows.InitializeCriticalSection(Lock);
// The list of protocol handlers
List := TStringList.Create;
end;
finalization
begin
// deactivate all handlers (should only happen when memory leaks are present...)
while List.Count > 0 do TInternetProtocol(List.Objects[0]).Active := False;
List.Free;
// and delete the critical section
Windows.DeleteCriticalSection(Lock);
end;
end.
用法會很好。 – kobik 2012-02-03 00:33:53
@kobik:註冊組件;在表單/數據模塊上使用組件,填寫屬性/事件並將活動設置爲true。運行應用程序,並瞧。 – 2012-02-03 21:51:38
@Eric:我真的不知道。你可以試試。只要安全允許,應該在32位IE中工作。 – 2013-09-27 15:53:37
來獲取文本出在Web瀏覽器中的PDF,我發現使用名爲PushKeys一個開源單元發送鍵將網頁瀏覽器的解決方案以選擇所有文本(控制 + 甲),將其複製到剪貼板(控制 + ç),然後將其粘貼到使用PasteFromClipBoard
一個TMemo
或其它控制。經過D2007測試。
WebBrowser.SetFocus; // set the focus to the TWebBrowser control
Sleep(1000); // 1 second delay to be sure webbrowser actually has focus
Application.ProcessMessages;
PushKeys('^a'); //send ctrl-a to select all text
Application.ProcessMessages;
WebBrowser.SetFocus;
PushKeys('^c'); //send ctrl-c to copy the text to clipboard
Sleep(1000); // 1 second delay to make sure clipboard finishes processing
Application.ProcessMessages;
Memo1.PasteFromClipBoard; // Paste the clipboard to a memo field.
// You could also use the clipbrd unit to handle the data.
//for Multi-page PDF's, you can send a PageDn key to get to the next page:
PushFnKey('PAGEDOWN');
是否必須是TWebBrowser?用Synapse或Indy來實現它應該很容易。 – mjn 2012-10-29 12:13:20