Advertisement
Guest User

Untitled

a guest
Aug 8th, 2019
234
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.60 KB | None | 0 0
  1. unit WinApiDownload;
  2.  
  3. interface
  4. uses Winapi.Windows, Winapi.WinInet, System.SysUtils, System.Classes;
  5.  
  6. type
  7. TEventWorkStart = procedure (Sender : TObject; iFileSize : Int64) of object;
  8. TEventWork = procedure (Sender : TObject; iBytesTransfered : Int64) of object;
  9. TEventWorkEnd = procedure (Sender : TObject; iBytesTransfered : Int64;
  10. ErrorCode : Integer) of object;
  11. TEventError = procedure (Sender : TObject; iErrorCode : Integer;
  12. sURL : string) of object;
  13.  
  14. TWinApiDownload = class(TObject)
  15. private
  16. fEventWorkStart : TEventWorkStart;
  17. fEventWork : TEventWork;
  18. fEventWorkEnd : TEventWorkEnd;
  19. fEventError : TEventError;
  20. fURL : string;
  21. fUserAgent : string;
  22. fStop : Boolean;
  23. fActive : Boolean;
  24. fCachingEnabled : Boolean;
  25. fProgressUpdateInterval : Cardinal;
  26. function GetIsActive : Boolean;
  27. public
  28. constructor Create;
  29. destructor Destroy; override;
  30. function CheckURL(aURL: string) : Integer;
  31. function Download(Stream : TStream) : Integer; overload;
  32. function Download(var res : string) : Integer; overload;
  33. function ErrorCodeToMessageString(aErrorCode : Integer) : string;
  34. procedure Stop;
  35. procedure Clear;
  36. property UserAgent : string read fUserAgent write fUserAgent;
  37. property URL : string read fURL write fURL;
  38. property DownloadActive : Boolean read GetIsActive;
  39. property CachingEnabled : Boolean read fCachingEnabled write fCachingEnabled;
  40. property UpdateInterval : Cardinal read fProgressUpdateInterval write fProgressUpdateInterval;
  41. property OnWorkStart : TEventWorkStart read fEventWorkStart write fEventWorkStart;
  42. property OnWork : TEventWork read fEventWork write fEventWork;
  43. property OnWorkEnd : TEventWorkEnd read fEventWorkEnd write fEventWorkEnd;
  44. property OnError : TEventError read fEventError write fEventError;
  45. end;
  46.  
  47. const
  48. DOWNLOAD_ERROR_UNKNOWN = -1;
  49. DOWNLOAD_ABORTED_BY_USER = -2;
  50. DOWNLOAD_ERROR_INCOMPLETE_READ = -3;
  51. DOWNLOAD_ERROR_DATA_READ = -4;
  52. DOWNLOAD_ERROR_EMPTY_URL = -5;
  53. DOWNLOAD_ERROR_DIR_NOT_EXISTS = -6;
  54. DOWNLOAD_ERROR_INCORRECT_DATA_SIZE = -7;
  55.  
  56. implementation
  57.  
  58. constructor TWinApiDownload.Create;
  59. begin
  60. inherited;
  61. fUserAgent := 'Mozilla/5.001 (windows; U; NT4.0; en-US; rv:1.0) Gecko/25250101';
  62. fProgressUpdateInterval := 100;
  63. fCachingEnabled := True;
  64. fStop := False;
  65. fActive := False;
  66. end;
  67.  
  68. destructor TWinApiDownload.Destroy;
  69. begin
  70. Stop;
  71. inherited;
  72. end;
  73.  
  74. function TWinApiDownload.CheckURL(aURL: string) : Integer;
  75. var
  76. hInet, hUrl : HINTERNET;
  77. dwBufferLen, dwIndex : DWORD;
  78. pErrorCode : array [0..255] of Char;
  79. begin
  80. fActive := True;
  81. if aURL = '' then
  82. begin
  83. Result := DOWNLOAD_ERROR_EMPTY_URL;
  84. fActive := False;
  85. Exit;
  86. end;
  87.  
  88. fStop := False;
  89. hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG,
  90. nil, nil, 0);
  91. if Assigned(hInet) then
  92. begin
  93. hUrl := InternetOpenUrl(hInet, PChar(aURL), nil, 0,0,0);
  94. if Assigned(hUrl) then
  95. begin
  96. dwIndex := 0;
  97. dwBufferLen := 20;
  98. HttpQueryInfo(hUrl, HTTP_QUERY_STATUS_CODE, @pErrorCode, dwBufferLen, dwIndex);
  99. Result := StrToInt(pErrorCode);
  100. InternetCloseHandle(hUrl);
  101. InternetCloseHandle(hInet);
  102. end else
  103. InternetCloseHandle(hInet);
  104. end else
  105. Result := DOWNLOAD_ERROR_UNKNOWN;
  106. if fStop then
  107. Result := DOWNLOAD_ABORTED_BY_USER;
  108. fActive := False;
  109. end;
  110.  
  111. function TWinApiDownload.Download(Stream : TStream) : Integer;
  112. var
  113. hInet, hUrl : HINTERNET;
  114. buf : array [0..4095] of Byte;
  115. lpdwNumberOfBytesAvailable : DWORD;
  116. dwBufferLen, dwIndex : DWORD;
  117. pSize, pErrorCode : array [0..255] of Char;
  118. b, iter : Cardinal;
  119. transfered, TargetSize, l : Int64;
  120. ErrorDataReadIncomplete, ErrorIncorrectSize : boolean;
  121. begin
  122. fActive := True;
  123. if URL = '' then
  124. begin
  125. Result := DOWNLOAD_ERROR_EMPTY_URL;
  126. fActive := False;
  127. Exit;
  128. end;
  129. if fStop then
  130. begin
  131. Result := DOWNLOAD_ABORTED_BY_USER;
  132. fActive := False;
  133. Exit;
  134. end;
  135. Result := DOWNLOAD_ERROR_UNKNOWN;
  136.  
  137. hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG,
  138. nil, nil, 0);
  139. if Assigned(hInet) then
  140. begin
  141. if CachingEnabled then
  142. hUrl := InternetOpenUrl(hInet, PChar(URL), nil, 0, 0, 0) else
  143. hUrl := InternetOpenUrl(hInet, PChar(URL), nil, 0,
  144. INTERNET_FLAG_NO_CACHE_WRITE,0);
  145. if Assigned(hUrl) then
  146. begin
  147. dwIndex := 0;
  148. dwBufferLen := 20;
  149. HttpQueryInfo(hUrl, HTTP_QUERY_STATUS_CODE, @pErrorCode, dwBufferLen, dwIndex);
  150. Result := StrToInt(pErrorCode);
  151. if Result <> 200 then
  152. begin
  153. InternetCloseHandle(hUrl);
  154. InternetCloseHandle(hInet);
  155. Exit;
  156. end;
  157. dwIndex := 0;
  158. dwBufferLen := 20;
  159. if HttpQueryInfo(hUrl, HTTP_QUERY_CONTENT_LENGTH, @pSize,
  160. dwBufferLen, dwIndex) then
  161. begin
  162. TargetSize := StrToInt(pSize);
  163. if Assigned(OnWorkStart) then
  164. OnWorkStart(Self, TargetSize);
  165. end else
  166. TargetSize := 0;
  167. transfered := 0;
  168. ErrorIncorrectSize := False;
  169. repeat
  170. if InternetQueryDataAvailable(hUrl,
  171. lpdwNumberOfBytesAvailable, 0, 0) then
  172. begin
  173. if lpdwNumberOfBytesAvailable > 0 then
  174. begin
  175. ZeroMemory(@buf, SizeOf(buf));
  176. if InternetReadFile(hUrl, @buf, SizeOf(buf), b) then
  177. begin
  178. if b > 0 then
  179. begin
  180. l := Stream.Size;
  181. transfered := transfered + b;
  182. Stream.WriteBuffer(buf, b);
  183. if Stream.Size <> l + b then
  184. begin
  185. ErrorIncorrectSize := True;
  186. Break;
  187. end;
  188. if lpdwNumberOfBytesAvailable > SizeOf(buf) then
  189. ErrorDataReadIncomplete := b < SizeOf(buf) else
  190. ErrorDataReadIncomplete := b < lpdwNumberOfBytesAvailable;
  191. if ErrorDataReadIncomplete then
  192. begin
  193. if Assigned(OnError) then
  194. begin
  195. OnError(Self, DOWNLOAD_ERROR_INCOMPLETE_READ, fURL);
  196. end;
  197. end else
  198. begin
  199. if Assigned(OnWork) then
  200. begin
  201. Inc(iter);
  202. if iter > fProgressUpdateInterval then
  203. begin
  204. OnWork(Self, transfered);
  205. iter := 0;
  206. end;
  207. end;
  208. end;
  209. end else
  210. begin
  211. ErrorDataReadIncomplete := True;
  212. Break;
  213. end;
  214. end else
  215. begin
  216. if Assigned(OnError) then
  217. begin
  218. OnError(Self, DOWNLOAD_ERROR_INCOMPLETE_READ, fURL);
  219. end;
  220. Result := DOWNLOAD_ERROR_DATA_READ;
  221. Break;
  222. end;
  223. end;
  224. end else
  225. begin
  226. Result := DOWNLOAD_ERROR_UNKNOWN;
  227. Break;
  228. end;
  229. until (lpdwNumberOfBytesAvailable = 0) or (b = 0) or
  230. (ErrorDataReadIncomplete) or (fStop);
  231. if fStop then
  232. Result := DOWNLOAD_ABORTED_BY_USER else
  233. if ErrorDataReadIncomplete then
  234. Result := DOWNLOAD_ERROR_INCOMPLETE_READ else
  235. if (transfered <> TargetSize) or (ErrorIncorrectSize) then
  236. Result := DOWNLOAD_ERROR_INCORRECT_DATA_SIZE;
  237. if Assigned(OnWorkEnd) then
  238. OnWorkEnd(Self, transfered, Result);
  239. InternetCloseHandle(hUrl);
  240. end;
  241. InternetCloseHandle(hInet);
  242. end;
  243. fActive := False;
  244. end;
  245.  
  246. function TWinApiDownload.Download(var res : string) : Integer;
  247. var
  248. hInet, hUrl : HINTERNET;
  249. buffer, buf : array [0..4095] of Byte;
  250. lpdwBufferLength: DWORD;
  251. lpdwReserved : DWORD;
  252. dwBytesRead : DWORD;
  253. lpdwNumberOfBytesAvailable : DWORD;
  254. dwBufferLen, dwIndex : DWORD;
  255. pSize, pErrorCode : array [0..255] of Char;
  256. b, _pos, iter, transfered : Cardinal;
  257. ResponseText : AnsiString;
  258. begin
  259. fActive := True;
  260. res := '';
  261. if URL = '' then
  262. begin
  263. Result := DOWNLOAD_ERROR_EMPTY_URL;
  264. fActive := False;
  265. Exit;
  266. end;
  267. Result := DOWNLOAD_ERROR_UNKNOWN;
  268.  
  269. hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG,
  270. nil, nil, 0);
  271. if Assigned(hInet) then
  272. begin
  273. if CachingEnabled then
  274. hUrl := InternetOpenUrl(hInet, PChar(URL), nil, 0, 0, 0) else
  275. hUrl := InternetOpenUrl(hInet, PChar(URL), nil, 0,
  276. INTERNET_FLAG_NO_CACHE_WRITE,0);
  277. if Assigned(hUrl) then
  278. begin
  279. dwIndex := 0;
  280. dwBufferLen := 20;
  281. HttpQueryInfo(hUrl, HTTP_QUERY_STATUS_CODE, @pErrorCode, dwBufferLen, dwIndex);
  282. Result := StrToInt(pErrorCode);
  283. if Result <> 200 then
  284. begin
  285. InternetCloseHandle(hUrl);
  286. InternetCloseHandle(hInet);
  287. Exit;
  288. end;
  289. dwIndex := 0;
  290. dwBufferLen := 20;
  291. if HttpQueryInfo(hUrl, HTTP_QUERY_CONTENT_LENGTH, @pSize,
  292. dwBufferLen, dwIndex) then
  293. // begin
  294. if Assigned(OnWorkStart) then
  295. OnWorkStart(Self, StrToInt(pSize));
  296. // end;
  297. ResponseText := '';
  298. _Pos := 1;
  299. iter := 0;
  300. transfered := 0;
  301. repeat
  302. if InternetQueryDataAvailable(hUrl,
  303. lpdwNumberOfBytesAvailable, 0, 0) then
  304. begin
  305. if lpdwNumberOfBytesAvailable > 0 then
  306. begin
  307. SetLength(ResponseText, Length(ResponseText) +
  308. lpdwNumberOfBytesAvailable);
  309. if InternetReadFile(hUrl, @responsetext[_pos],
  310. lpdwNumberOfBytesAvailable, b) then
  311. begin
  312. inc(_pos, b);
  313. inc(transfered, b);
  314. if Assigned(OnWork) then
  315. begin
  316. inc(iter);
  317. if iter >= fProgressUpdateInterval then
  318. begin
  319. OnWork(Self, transfered);
  320. iter := 0;
  321. end;
  322. end;
  323. end;
  324. end;
  325. end;
  326. until (lpdwNumberOfBytesAvailable = 0) or (b = 0) or (fStop);
  327. if fStop then
  328. Result := DOWNLOAD_ABORTED_BY_USER;
  329. res := UTF8ToString(ResponseText);
  330. if Assigned(fEventWorkEnd) then
  331. OnWorkEnd(Self, transfered, Result);
  332. InternetCloseHandle(hUrl);
  333. end;
  334. InternetCloseHandle(hInet);
  335. end;
  336. fActive := False;
  337. end;
  338.  
  339. procedure TWinApiDownload.Stop;
  340. begin
  341. fStop := True;
  342. end;
  343.  
  344. procedure TWinApiDownload.Clear;
  345. begin
  346. fStop := False;
  347. end;
  348.  
  349. function TWinApiDownload.GetIsActive;
  350. begin
  351. Result := fActive;
  352. end;
  353.  
  354. function TWinApiDownload.ErrorCodeToMessageString(aErrorCode: Integer) : string;
  355. begin
  356. case aErrorCode of
  357. 403:
  358. Result := 'Forbidden';
  359. 404:
  360. Result := 'Not found';
  361. DOWNLOAD_ERROR_UNKNOWN:
  362. Result := 'Unknown error';
  363. DOWNLOAD_ERROR_EMPTY_URL:
  364. Result := 'Empty URL';
  365. DOWNLOAD_ABORTED_BY_USER:
  366. Result := 'Canceled by user';
  367. DOWNLOAD_ERROR_INCOMPLETE_READ:
  368. Result := 'Incomplete read';
  369. DOWNLOAD_ERROR_DATA_READ:
  370. Result := 'Data read error';
  371. DOWNLOAD_ERROR_INCORRECT_DATA_SIZE:
  372. Result := 'Incorrect data size';
  373. else
  374. Result := IntToStr(aErrorCode) + ': Unknown error';
  375. end;
  376. end;
  377.  
  378. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement