I don't care whether it is a string, stringlist, memo, etc ... but not a disk file
How do I download a compete web page into a variable? Thanks
Using Indy:
uses IdHTTP;
const
HTTP_RESPONSE_OK = 200;
function GetPage(aURL: string): string;
var
Response: TStringStream;
HTTP: TIdHTTP;
begin
Result := '';
Response := TStringStream.Create('');
try
HTTP := TIdHTTP.Create(nil);
try
HTTP.Get(aURL, Response);
if HTTP.ResponseCode = HTTP_RESPONSE_OK then begin
Result := Response.DataString;
end else begin
// TODO -cLogging: add some logging
end;
finally
HTTP.Free;
end;
finally
Response.Free;
end;
end;
Using the native Microsoft Windows WinInet API:
function WebGetData(const UserAgent: string; const URL: string): string;
var
hInet: HINTERNET;
hURL: HINTERNET;
Buffer: array[0..1023] of AnsiChar;
BufferLen: cardinal;
begin
result := '';
hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if hInet = nil then RaiseLastOSError;
try
hURL := InternetOpenUrl(hInet, PChar(URL), nil, 0, 0, 0);
if hURL = nil then RaiseLastOSError;
try
repeat
if not InternetReadFile(hURL, #Buffer, SizeOf(Buffer), BufferLen) then
RaiseLastOSError;
result := result + UTF8Decode(Copy(Buffer, 1, BufferLen))
until BufferLen = 0;
finally
InternetCloseHandle(hURL);
end;
finally
InternetCloseHandle(hInet);
end;
end;
Try it:
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Text := WebGetData('My Own Client', 'http://www.bbc.co.uk')
end;
But this only works if the encoding is UTF-8. So, to make it work in other cases, you either have to handle these separately, or you can use the Indy high-level wrappers, as suggested by Marjan. I admit they are superior in this case, but I still want to promote the underlying API, if for no other reason than educational...
Related
Hi I have the following code:
procedure TformInvoiceDetails.ReadWebImage(imgAddress: string);
var
memStream: TMemoryStream;
begin
memStream := TMemoryStream.Create;
try
IdHTTP1.Get (imgAddress,memStream);
//sleep(5000);
except
imageContProduct.Visible := false;
ShowMessage('Image not found at:'+imgAddress);
memStream.Free;
exit;
end;
try
memStream.Position := 0;
imageContProduct.Visible := true;
imageContProduct.Bitmap.LoadFromStream(memStream);
finally
memStream.Free;
end;
end;
Most of the time it works okay but I keep getting an exeption error and sometimes a 'Image not found at' ( although the image does exist).
If I put the sleep(5000) everything works okay.
So I am presuming the image has not been recived before I try and add to the TImage.
Is there a better method to use ?
You can use another components to load pictures:
uses WinInet, JPEG;
...
function DownloadToStream(Url: string; Stream: TStream): Boolean;
var
hNet: HINTERNET;
hUrl: HINTERNET;
Buffer: array[0..10240] of Char;
BytesRead: DWORD;
begin
Result := FALSE;
hNet := InternetOpen('agent', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if (hNet <> nil) then
begin
hUrl := InternetOpenUrl(hNet, PChar(Url), nil, 0,
INTERNET_FLAG_RELOAD, 0);
if (hUrl <> nil) then
begin
while (InternetReadFile(hUrl, #Buffer, sizeof(Buffer), BytesRead)) do
begin
if (BytesRead = 0) then
begin
Result := TRUE;
break;
end;
Stream.WriteBuffer(Buffer,BytesRead);
end;
InternetCloseHandle(hUrl);
end;
InternetCloseHandle(hNet);
end;
end;
procedure TformInvoiceDetails.ReadWebImage(imgAddress: string);
var
memStream: TMemoryStream;
Jpg:= TJPEGImage;
begin
memStream:= TMemoryStream.Create;
try
if DownloadToStream(imgAddress, memStream) then
begin
memStream.Seek(0, soFromBeginning);
if (LowerCase(RightStr(imgAddress, 4))='.jpg') or (LowerCase(RightStr(imgAddress, 5))='.jpeg')
try //do the same operation for *.png
Jpg:= TJPEGImage.Create;
Jpg.LoadFromStream(memStream);
imageContProduct.Picture.Bitmap.Assign(Jpg);
imageContProduct.Visible := true;
finally
Jpg.Free;
end
else
try
imageContProduct.Picture.Bitmap.LoadFromStream(memStream);
imageContProduct.Visible := true;
finally
end;
end;
finally
memStream.Free;
end;
end;
I am trying to get the reg_binary as string from a registry key.
This is my function
function ReadBinString(key: string; AttrName: string): string;
var
ReadStr: TRegistry;
begin
// Result := '';
ReadStr := TRegistry.Create(KEY_WRITE OR KEY_WOW64_64KEY);
ReadStr.RootKey := HKEY_LOCAL_MACHINE;
if ReadStr.OpenKey(key, true) then
begin
Result := ReadStr.GetDataAsString(AttrName);
end;
ReadStr.CloseKey;
ReadStr.Free;
end;
and here is my registry key Export :
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\ZES\ACINFO]
"iamthere"=dword:00000001
"ArrayOrder"=hex:4d,79,45,78,63,6c,75,64,65
the problem is , the function returns empty string
I even tried running as administrator to make sure that it is not permissions.
Any help ?
Expanding on my comment to the question, I'd use code like so:
function ReadBinString(RootKey: HKEY; Access: LongWord; const KeyName,
ValueName: string; Encoding: TEncoding): string;
var
Registry: TRegistry;
Bytes: TBytes;
begin
Registry := TRegistry.Create(Access);
try
Registry.RootKey := RootKey;
if Registry.OpenKeyReadOnly(KeyName) then begin
SetLength(Bytes, Registry.GetDataSize(ValueName));
Registry.ReadBinaryData(ValueName, Pointer(Bytes)^, Length(Bytes));
Result := Encoding.GetString(Bytes);
end else begin
Result := '';
end;
finally
Registry.Free;
end;
end;
For your data you would call it like so:
Value := ReadBinString(HKEY_LOCAL_MACHINE, KEY_WOW64_64KEY, 'Software\ZES\ACINFO',
'ArrayOrder', TEncoding.ANSI);
Notes:
I have avoided hard-coding the root key.
I have used TEncoding to decode the byte array to text. This is far more effective than GetDataAsString.
I have allowed the caller to specify the encoding to be used.
I have allowed the caller to specify the access flags.
I have used OpenKeyReadOnly because we do not require write access.
Thanks to David Heffernan I came with this solution:
function ReadBinString(key: string; AttrName: string): string;
var
ReadStr: TRegistry;
hexStr : string;
I : Integer;
begin
// Result := '';
ReadStr := TRegistry.Create(KEY_READ OR KEY_WOW64_64KEY);
ReadStr.RootKey := HKEY_LOCAL_MACHINE;
if ReadStr.OpenKey(key, true) then
begin
hexStr := ReadStr.GetDataAsString(AttrName);
hexStr := hexStr.Replace(',','');
for I := 1 to length (hexStr) div 2 do
Result:= Result+Char(StrToInt('$'+Copy(hexStr,(I-1)*2+1,2)));
end;
ReadStr.CloseKey;
ReadStr.Free;
end;
Thanks to David Heffernan again ... this worked for me :
function ReadBinString(key: string; AttrName: string): string;
var
ReadStr: TRegistry;
hexStr: string;
I: Integer;
Bytes: TBytes;
Encoding: TEncoding;
begin
Encoding := TEncoding.ANSI;
Result := '';
ReadStr := TRegistry.Create(KEY_READ OR KEY_WOW64_64KEY);
ReadStr.RootKey := HKEY_LOCAL_MACHINE;
try
if ReadStr.OpenKeyReadOnly(key ) then
begin
SetLength(Bytes, ReadStr.GetDataSize(AttrName));
ReadStr.ReadBinaryData(AttrName, Pointer(Bytes)^, Length(Bytes));
Result := Encoding.GetString(Bytes);
// hexStr := ReadStr.GetDataAsString(AttrName);
//
// hexStr := hexStr.Replace(',','');
// for I := 1 to length (hexStr) div 2 do
// Result:= Result+Char(StrToInt('$'+Copy(hexStr,(I-1)*2+1,2)));
end;
except
end;
ReadStr.CloseKey;
ReadStr.Free;
end;
How can I get all the exported functions from a DLL, programmatically? I am trying to compare two DLL's for exported functions.
This is the code that I use:
uses
System.Classes, Winapi.Windows;
type
PIMAGE_NT_HEADERS = ^IMAGE_NT_HEADERS;
PIMAGE_EXPORT_DIRECTORY = ^IMAGE_EXPORT_DIRECTORY;
function ImageNtHeader(Base: Pointer): PIMAGE_NT_HEADERS; stdcall; external 'dbghelp.dll';
function ImageRvaToVa(NtHeaders: Pointer; Base: Pointer; Rva: ULONG; LastRvaSection: Pointer): Pointer; stdcall; external 'dbghelp.dll';
procedure EnumerateImageExportedFunctionNames(const ImageName: string; NamesList: TStrings);
var
i: Integer;
FileHandle: THandle;
ImageHandle: THandle;
ImagePointer: Pointer;
Header: PIMAGE_NT_HEADERS;
ExportTable: PIMAGE_EXPORT_DIRECTORY;
NamesPointer: Pointer;
NamesPtr: PCardinal;
NamePtr: PAnsiChar;
begin
//NOTE: our policy in this procedure is to exit upon any failure and return and empty list
NamesList.Clear;
FileHandle := CreateFile(
PChar(ImageName),
GENERIC_READ,
FILE_SHARE_READ,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0
);
if FileHandle=INVALID_HANDLE_VALUE then begin
exit;
end;
Try
ImageHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil);
if ImageHandle=0 then begin
exit;
end;
Try
ImagePointer := MapViewOfFile(ImageHandle, FILE_MAP_READ, 0, 0, 0);
if not Assigned(ImagePointer) then begin
exit;
end;
Try
Header := ImageNtHeader(ImagePointer);
if not Assigned(Header) then begin
exit;
end;
if Header.Signature<>$00004550 then begin // "PE\0\0" as a DWORD.
exit;
end;
ExportTable := ImageRvaToVa(Header, ImagePointer, Header.OptionalHeader.DataDirectory[0].VirtualAddress, nil);
if not Assigned(ExportTable) then begin
exit;
end;
NamesPtr := ImageRvaToVa(Header, ImagePointer, Cardinal(ExportTable.AddressOfNames), nil);
if not Assigned(NamesPtr) then begin
exit;
end;
for i := 0 to ExportTable.NumberOfNames-1 do begin
NamePtr := ImageRvaToVa(Header, ImagePointer, NamesPtr^, nil);
if not Assigned(NamePtr) then begin
exit;
end;
NamesList.Add(NamePtr);
inc(NamesPtr);
end;
Finally
UnmapViewOfFile(ImagePointer); // Ignore error as there is not much we could do.
End;
Finally
CloseHandle(ImageHandle);
End;
Finally
CloseHandle(FileHandle);
End;
end;
I came here to find a way to list all functions contained within an ocx (which is basically a dll). All infos here didn't give me what I was looking for. But then I found the free dllexp.exe from nirsoft (https://www.nirsoft.net/utils/dll_export_viewer.html).
Direct download link: https://www.nirsoft.net/packages/progtools.zip which perfectly shows all exported functions of a dll/ocx and is very user-friendly.
I need to access binary image data using XMLHttpRequest in Delphi. I am using the following code but its not working, could someone please tell me what's wrong with this code, thanks in advance.
//I am using this function to get Image Binary data into Memory Stream.
procedure SendGETRequest(p_Url: string; p_resStream: TMemoryStream);
begin
FXmlHttpReq.open(METHOD_GET, p_Url, false, FUsername, FPassword);
FXmlHttpReq.setRequestHeader(HTTP_AUTHENTICATION, HTTP_BASIC + EncodeBase64(
FUsername + ':'+FPassword));
FXmlHttpReq.setRequestHeader(HTTP_CACHE_CONTROL, HTTP_NO_CACHE);
//FXmlHttpReq.setRequestHeader('Content-type','application/octet-stream');
FXmlHttpReq.send('');
if not VarIsEmpty(FXmlHttpReq.responseBody) then
begin
p_resStream:= OleVariantToMemoryStream(FXmlHttpReq.responseStream);
end;//if...
end;
function OleVariantToMemoryStream(OV: OleVariant): TMemoryStream;
var
Data: PByteArray;
Size: integer;
begin
Result := TMemoryStream.Create;
try
Size := VarArrayHighBound (OV, 1) - VarArrayLowBound(OV, 1) + 1;
Data := VarArrayLock(OV);
try
Result.Position := 0;
Result.WriteBuffer(Data^, Size);
finally
VarArrayUnlock(OV);
end;
except
Result.Free;
Result := nil;
end;
end;
responseStream is IStream. You need to convert it using TOleStream (AxCtrls):
uses AxCtrls, ComObj, ActiveX;
procedure TForm1.Button1Click(Sender: TObject);
var
oXMLHTTP: OleVariant;
MemoryStream: TMemoryStream;
Stream: IStream;
OleStream: TOleStream;
begin
oXMLHTTP := CreateOleObject('MSXML2.XMLHTTP.3.0');
oXMLHTTP.open('GET', 'https://www.google.com/images/srpr/logo11w.png', False);
oXMLHTTP.send(EmptyParam);
Stream := IUnknown(oXMLHTTP.ResponseStream) as IStream;
OleStream := TOleStream.Create(Stream);
try
OleStream.Position := 0;
MemoryStream := TMemoryStream.Create;
try
MemoryStream.CopyFrom(OleStream, OleStream.Size);
MemoryStream.SaveToFile('logo11w.png');
finally
MemoryStream.Free;
end;
finally
OleStream.Free;
end;
end;
Delphi 6 Prof, Win7 OS.
I have this code to get the file size by URL:
function TDDWIToolObject.GetFileSize(out Size: Int64): boolean;
var
hInet: HINTERNET;
hRequest : HINTERNET;
lpdwBufferLength: DWORD;
lpdwReserved : DWORD;
ServerName: string;
Resource: string;
FileSizeBuffer : array[0..32] of char;
//SizeCard : Cardinal;
begin
ParseURL(Url, ServerName, Resource);
Result := False;
Size := 0;
hInet := InternetOpen(PChar(_UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if hInet=nil then begin
FErrorCode := GetLastError;
Exit;
end;
try
hRequest := InternetOpenUrl(hInet, PChar(URL), PCHar(Headers), Length(HEaders), 0, 0);
try
FillChar(FileSizeBuffer, SizeOf(FileSizeBuffer), #0);
lpdwBufferLength := SizeOf(FileSizeBuffer);
lpdwReserved :=0;
if not HttpQueryInfo(
hRequest,
HTTP_QUERY_CONTENT_LENGTH,
#FileSizeBuffer, lpdwBufferLength, lpdwReserved) then begin
FErrorCode:=GetLastError;
Exit;
end;
Size := StrToInt64(StrPas(FileSizeBuffer));
Result := True;
finally
InternetCloseHandle(hRequest);
end;
finally
InternetCloseHandle(hInet);
end;
end;
It is working good with my machine + DSL connection.
But when I check this code in other place which is fully protected (proxy + many policies) then I get error code 12150... :-(
What is interesting, that I can download this file, when I use this code:
function TDDWIToolObject.DownloadFile;
var
hInet: HINTERNET;
hFile: HINTERNET;
pbuffer: Pointer;
bytesRead: DWORD;
Stm : TFileStream;
TotalBytes : Int64;
AbortIt : boolean;
begin
Result := False;
FErrorCode := -1;
FAborted := False;
hInet := InternetOpen(PChar(_UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if hInet = nil
then begin
FErrorCode := GetLastError;
Exit;
end;
try
hFile := InternetOpenURL(hInet, PChar(URL), PChar(FHeaders), Length(FHeaders), 0, 0);
if hFile = nil
then begin
FErrorCode := GetLastError;
Exit;
end;
try
Stm := TFileStream.Create(FN, fmCreate);
try
GetMem(pbuffer, FBufferSize);
try
TotalBytes := 0; AbortIt := False;
while (not FAborted) do begin
if not InternetReadFile(hFile, pbuffer, FBufferSize, bytesRead) then begin
FErrorCode := GetLastError;
Exit;
end;
if bytesRead > 0 then begin
Stm.WriteBuffer(pbuffer^, bytesRead);
if Assigned(FOnBytesArrived)
then begin
inc(TotalBytes, bytesRead);
FOnBytesArrived(Self, TotalBytes, AbortIt);
if AbortIt
then Abort;
end;
end else begin
break;
end;
end;
finally
FreeMem(pbuffer);
end;
if not FAborted
then Result := True;
finally
Stm.Free;
end;
finally
InternetCloseHandle(hFile);
end;
finally
InternetCloseHandle(hInet);
end;
end;
It is interesting because sysadmin allowed the requests to this URL in proxy, and the downloads work for me - only the content length requests fail.
I want to ask one question, but it is hard to do, because many of them is in my mind...
Do you have some idea what we can do to allow the requests?
Maybe HttpRequest uses another port, or some "illegal" what isn't proxiable?
Or my code is seems to be wrong? Why it is working in nonprotected area? What are the differents between download and get content length requests?
So the question is as in summarized format: do you have some idea what can I do to I get the file size before downloading?
Thanks for it.
This error can be caused by many factors (ERROR_HTTP_HEADER_NOT_FOUND), in your code you are not checking the result of the InternetOpenUrl function before to call the HttpQueryInfo method, and I don't see the content of the _UserAgent and Headers variables to give you a more exact answer. Anyway try using the HttpOpenRequest and HttpSendRequest functions instead of InternetOpenURL.
Try this sample
uses
Windows,
SysUtils,
WinInet;
const
sUserAgent = 'Mozilla/5.001 (windows; U; NT4.0; en-US; rv:1.0) Gecko/25250101';
function GetWinInetError(ErrorCode:Cardinal): string;
const
winetdll = 'wininet.dll';
var
Len: Integer;
Buffer: PChar;
begin
Len := FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE or FORMAT_MESSAGE_FROM_SYSTEM or
FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_IGNORE_INSERTS or FORMAT_MESSAGE_ARGUMENT_ARRAY,
Pointer(GetModuleHandle(winetdll)), ErrorCode, 0, #Buffer, SizeOf(Buffer), nil);
try
while (Len > 0) and {$IFDEF UNICODE}(CharInSet(Buffer[Len - 1], [#0..#32, '.'])) {$ELSE}(Buffer[Len - 1] in [#0..#32, '.']) {$ENDIF} do Dec(Len);
SetString(Result, Buffer, Len);
finally
LocalFree(HLOCAL(Buffer));
end;
end;
procedure ParseURL(const lpszUrl: string; var Host, Resource: string);
var
lpszScheme : array[0..INTERNET_MAX_SCHEME_LENGTH - 1] of Char;
lpszHostName : array[0..INTERNET_MAX_HOST_NAME_LENGTH - 1] of Char;
lpszUserName : array[0..INTERNET_MAX_USER_NAME_LENGTH - 1] of Char;
lpszPassword : array[0..INTERNET_MAX_PASSWORD_LENGTH - 1] of Char;
lpszUrlPath : array[0..INTERNET_MAX_PATH_LENGTH - 1] of Char;
lpszExtraInfo : array[0..1024 - 1] of Char;
lpUrlComponents : TURLComponents;
begin
ZeroMemory(#lpszScheme, SizeOf(lpszScheme));
ZeroMemory(#lpszHostName, SizeOf(lpszHostName));
ZeroMemory(#lpszUserName, SizeOf(lpszUserName));
ZeroMemory(#lpszPassword, SizeOf(lpszPassword));
ZeroMemory(#lpszUrlPath, SizeOf(lpszUrlPath));
ZeroMemory(#lpszExtraInfo, SizeOf(lpszExtraInfo));
ZeroMemory(#lpUrlComponents, SizeOf(TURLComponents));
lpUrlComponents.dwStructSize := SizeOf(TURLComponents);
lpUrlComponents.lpszScheme := lpszScheme;
lpUrlComponents.dwSchemeLength := SizeOf(lpszScheme);
lpUrlComponents.lpszHostName := lpszHostName;
lpUrlComponents.dwHostNameLength := SizeOf(lpszHostName);
lpUrlComponents.lpszUserName := lpszUserName;
lpUrlComponents.dwUserNameLength := SizeOf(lpszUserName);
lpUrlComponents.lpszPassword := lpszPassword;
lpUrlComponents.dwPasswordLength := SizeOf(lpszPassword);
lpUrlComponents.lpszUrlPath := lpszUrlPath;
lpUrlComponents.dwUrlPathLength := SizeOf(lpszUrlPath);
lpUrlComponents.lpszExtraInfo := lpszExtraInfo;
lpUrlComponents.dwExtraInfoLength := SizeOf(lpszExtraInfo);
InternetCrackUrl(PChar(lpszUrl), Length(lpszUrl), ICU_DECODE or ICU_ESCAPE, lpUrlComponents);
Host := lpszHostName;
Resource := lpszUrlPath;
end;
function GetRemoteFileSize(const Url : string): Integer;
var
hInet : HINTERNET;
hConnect : HINTERNET;
hRequest : HINTERNET;
lpdwBufferLength: DWORD;
lpdwReserved : DWORD;
ServerName: string;
Resource: string;
ErrorCode : Cardinal;
begin
ParseURL(Url,ServerName,Resource);
Result:=0;
hInet := InternetOpen(PChar(sUserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if hInet=nil then
begin
ErrorCode:=GetLastError;
raise Exception.Create(Format('InternetOpen Error %d Description %s',[ErrorCode,GetWinInetError(ErrorCode)]));
end;
try
hConnect := InternetConnect(hInet, PChar(ServerName), INTERNET_DEFAULT_HTTP_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);
if hConnect=nil then
begin
ErrorCode:=GetLastError;
raise Exception.Create(Format('InternetConnect Error %d Description %s',[ErrorCode,GetWinInetError(ErrorCode)]));
end;
try
hRequest := HttpOpenRequest(hConnect, PChar('HEAD'), PChar(Resource), nil, nil, nil, 0, 0);
if hRequest<>nil then
begin
try
lpdwBufferLength:=SizeOf(Result);
lpdwReserved :=0;
if not HttpSendRequest(hRequest, nil, 0, nil, 0) then
begin
ErrorCode:=GetLastError;
raise Exception.Create(Format('HttpOpenRequest Error %d Description %s',[ErrorCode,GetWinInetError(ErrorCode)]));
end;
if not HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH or HTTP_QUERY_FLAG_NUMBER, #Result, lpdwBufferLength, lpdwReserved) then
begin
Result:=0;
ErrorCode:=GetLastError;
raise Exception.Create(Format('HttpQueryInfo Error %d Description %s',[ErrorCode,GetWinInetError(ErrorCode)]));
end;
finally
InternetCloseHandle(hRequest);
end;
end
else
begin
ErrorCode:=GetLastError;
raise Exception.Create(Format('HttpOpenRequest Error %d Description %s',[ErrorCode,GetWinInetError(ErrorCode)]));
end;
finally
InternetCloseHandle(hConnect);
end;
finally
InternetCloseHandle(hInet);
end;
end;