当前位置: 首页 > news >正文

如何使用 URLOpenStream 函数 - 回复 天泽 的问题


URLOpenStream 和 URLDownloadToFile 类似, 都是下载文件的 COM 函数;

前者是下载到 IStream 流, 后者是直接下载到指定路径; 不如后者使用方便.

它们都声明在 UrlMon 单元, 本例还要同时 uses ActiveX, 因为要用到 IStream 接口.

function URLOpenStream(
  p1: IUnknown;            { 接口, 不用它, 给 nil 即可 }
  p2: PWideChar;           { 要下载的路径 }
  p3: DWORD;               { 暂未使用的参数, 须是 0 }
  p4: IBindStatusCallback  { 接口, 下载后的数据得给它要; 我们需要实现它 }
): HResult; stdcall;       { 返回 S_OK 表示成功, 本例是使用了 Succeeded 函数判断的 }

IBindStatusCallback 接口有八个方法(或事件), 用到用不到都得给简单实现下;
我们主要实现的是其中的 OnDataAvailable, 因为下载后的数据是通过其 stgmed 参数返回的.

下面是实现及测试代码:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, UrlMon, ActiveX;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  end;

  TBindStatusCallback = class(TInterfaceList, IBindStatusCallback)
  public
    function OnStartBinding(dwReserved: DWORD; pib: IBinding): HResult; stdcall;
    function GetPriority(out nPriority): HResult; stdcall;
    function OnLowResource(reserved: DWORD): HResult; stdcall;
    function OnProgress(ulProgress, ulProgressMax, ulStatusCode: ULONG;
      szStatusText: LPCWSTR): HResult; stdcall;
    function OnStopBinding(hresult: HResult; szError: LPCWSTR): HResult; stdcall;
    function GetBindInfo(out grfBINDF: DWORD; var bindinfo: TBindInfo): HResult; stdcall;
    function OnDataAvailable(grfBSCF: DWORD; dwSize: DWORD; formatetc: PFormatEtc;
      stgmed: PStgMedium): HResult; stdcall;
    function OnObjectAvailable(const iid: TGUID; punk: IUnknown): HResult; stdcall;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  url: string;
  MyBindStatusCallback: IBindStatusCallback;
begin
  Button1.Caption := '正在下载...';
  Button1.Enabled := False;

  url := 'http://files.cnblogs.com/del/PMark_1.rar';
  MyBindStatusCallback := TBindStatusCallback.Create;
  if Succeeded(URLOpenStream(nil, PChar(url), 0, MyBindStatusCallback)) then
    Button1.Caption := '下载完毕!'
  else
    Button1.Caption := '下载失败!';

  Button1.Enabled := True;
end;

{ TBindStatusCallback }

function TBindStatusCallback.GetBindInfo(out grfBINDF: DWORD;
  var bindinfo: TBindInfo): HResult;
begin
  Result := S_OK;
end;

function TBindStatusCallback.GetPriority(out nPriority): HResult;
begin
  Result := S_OK;
end;

function TBindStatusCallback.OnDataAvailable(grfBSCF, dwSize: DWORD;
  formatetc: PFormatEtc; stgmed: PStgMedium): HResult;
var
  Stream: IStream;
  mem: TMemoryStream;
begin
  if dwSize > 0 then
  begin
    Stream := IStream(stgmed.stm);
    mem := TMemoryStream.Create;
    mem.SetSize(dwSize);
    Stream.Read(mem.Memory, dwSize, nil);
    //ShowMessage(IntToStr(mem.Size));
    mem.SaveToFile('C:\Temp\PMark_1.rar');
    mem.Free;
    Result := S_OK;
  end else Result := E_ABORT;
end;

function TBindStatusCallback.OnLowResource(reserved: DWORD): HResult;
begin
  Result := S_OK;
end;

function TBindStatusCallback.OnObjectAvailable(const iid: TGUID;
  punk: IInterface): HResult;
begin
  Result := S_OK;
end;

function TBindStatusCallback.OnProgress(ulProgress, ulProgressMax,
  ulStatusCode: ULONG; szStatusText: LPCWSTR): HResult;
begin
  //如果需要下载进度就在这里写代码
  Result := S_OK;
end;

function TBindStatusCallback.OnStartBinding(dwReserved: DWORD;
  pib: IBinding): HResult;
begin
  Result := S_OK;
end;

function TBindStatusCallback.OnStopBinding(hresult: HResult;
  szError: LPCWSTR): HResult;
begin
  Result := S_OK;
end;

end.

相关文章:

  • 超强IIS站点工具一键设置PHP,支持多个PHP同时运行
  • 0101 项目经理的精神病(一)孤独
  • 锋利的jQuery-----读书笔记
  • Windows Mobile 6.5 配置环境,数据库访问,部署简单实例
  • KMP 算法(1):如何理解 KMP
  • 自己编写站内搜索
  • E. XOR and Favorite Number
  • VC精确计算代码执行时间
  • JS 时间戳转星期几 AND js时间戳判断时间几天前
  • 《软件设计精要与模式》第二版出版
  • ES2017异步函数现已正式可用
  • Windows2008server R2 组策略批量更改本地管理员密码
  • 常用国名与首都(英文)
  • autodesk fbx sdk sample里面的工程无法调试解决方法
  • NVelocity:语法
  • JavaScript-如何实现克隆(clone)函数
  • “大数据应用场景”之隔壁老王(连载四)
  • Java到底能干嘛?
  • Redux系列x:源码分析
  • underscore源码剖析之整体架构
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 阿里云前端周刊 - 第 26 期
  • 半理解系列--Promise的进化史
  • 从零搭建Koa2 Server
  • 分布式事物理论与实践
  • 想写好前端,先练好内功
  • 用简单代码看卷积组块发展
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • # C++之functional库用法整理
  • (4)Elastix图像配准:3D图像
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (附源码)ssm教师工作量核算统计系统 毕业设计 162307
  • (机器学习-深度学习快速入门)第三章机器学习-第二节:机器学习模型之线性回归
  • ******之网络***——物理***
  • .FileZilla的使用和主动模式被动模式介绍
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .net Stream篇(六)
  • .Net 代码性能 - (1)
  • .Net开发笔记(二十)创建一个需要授权的第三方组件
  • .NET企业级应用架构设计系列之技术选型
  • .NET设计模式(7):创建型模式专题总结(Creational Pattern)
  • .Net转Java自学之路—SpringMVC框架篇六(异常处理)
  • @data注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • []我的函数库
  • [1159]adb判断手机屏幕状态并点亮屏幕
  • [16/N]论得趣
  • [Android] 240204批量生成联系人,短信,通话记录的APK
  • [Angular 基础] - 指令(directives)
  • [C++]STL之map
  • [C++11 多线程同步] --- 条件变量的那些坑【条件变量信号丢失和条件变量虚假唤醒(spurious wakeup)】
  • [CF703D]Mishka and Interesting sum/[BZOJ5476]位运算
  • [GDOUCTF 2023]<ez_ze> SSTI 过滤数字 大括号{等
  • [Java、Android面试]_10_Java中==与equal()方法的区别?重写equal()方法?
  • [LeetBook]【学习日记】数组内乘积