现在开发客户端程序,主流的开发语言中Java、.Net很容易破解,MFC开发效率低,Delphi7是巅峰,后面走了弯路,现在XE系列一言难尽。至于QT,哎。

VB6现在已经基本退出历史舞台,惋惜的话就不多说了。。

最近楼主看上了FreeBasic,其国内的版本叫VisualFreeBasic(下面简称vfb),开发者勇芳是一位技术大牛。

vfb自带一个浏览器组件,封装的是国内一个浏览器大咖龙泉扫地僧的Miniblink。作为一个浏览器组件,竟然没有提供文件下载的案例,为此我跟VFB的一位技术大牛驰骋乾坤准备为此做一个例子。

Miniblink的免费版本node.dll导出的是纯C接口, 也就是__cdecl,而不是常见的__stdcall,这个也给增加了一些麻烦。收费版本mb.dll则采用stdcall接口,但是我们秉着不改vfb的浏览器组件的原则写例子,等下面有时间,我们再写个vfb的控件。

Miniblink下载有两个事件,分别是wkeDownload和wkeDownload2

wkeDownload的声明区别如下:

void wkeOnDownload(wkeWebView webView, wkeDownloadCallback callback, void* param)typedef bool(WKE_CALL_TYPE*wkeDownloadCallback)(wkeWebView webView, void* param, const char* url);

从上面的回调可以看出,wkeDownload只返回了一个url,对于没有身份认证、GET的请求才能下载,很鸡肋。

wkeDownload2的声明就复杂多了:

typedef void* wkeNetJob;typedef enum _wkeLoadingResult {WKE_LOADING_SUCCEEDED,WKE_LOADING_FAILED,WKE_LOADING_CANCELED
} wkeLoadingResult;typedef enum _wkeDownloadOpt {kWkeDownloadOptCancel,kWkeDownloadOptCacheData,
} wkeDownloadOpt;typedef void(WKE_CALL_TYPE*wkeNetJobDataRecvCallback)(void* ptr, wkeNetJob job, const char* data, int length);
typedef void(WKE_CALL_TYPE*wkeNetJobDataFinishCallback)(void* ptr, wkeNetJob job, wkeLoadingResult result);typedef struct _wkeNetJobDataBind {void* param;wkeNetJobDataRecvCallback recvCallback;wkeNetJobDataFinishCallback finishCallback;
}wkeNetJobDataBind;typedef wkeDownloadOpt(WKE_CALL_TYPE*wkeDownload2Callback)(wkeWebView webView, void* param, size_t expectedContentLength, const char* url, const char* mime, const char* disposition, wkeNetJob job, wkeNetJobDataBind* dataBind);Type DownInfo FileName As StringLength As IntegerDown As Integer
End Type

这个确实完善多了,但是对接的难度也大,估计也是因为这个市面上没见过如何使用这个接口的例子。vfb封装了wkeDownload2的事件,但是具体怎么写没有例子。

首先,我们根据C++的文档,声明两个枚举和一个结构体wkeNetJobDataBind。要特别注意的是,wkeNetJobDataBind的两个回调,得声明是cdecl导出的,不然这个接口wkeNetJobDataRecvCallback只会被调用一次,然后程序就会平栈错误直接崩溃(这里特别感谢驰骋乾坤的指点,不然我找不出这个BUG)。

enum wkeLoadingResultWKE_LOADING_SUCCEEDEDWKE_LOADING_FAILEDWKE_LOADING_CANCELED
End enumenum wkeDownloadOptkWkeDownloadOptCancelkWkeDownloadOptCacheData
End enumType DownInfo FileName As StringLength As IntegerDown As Integer
End TypeType wkeNetJobDataBindparam          As Any PtrrecvCallback   As Sub cdecl(param As Any Ptr ,job As wkeNetJob ,dataIn As Any Ptr ,length As Integer)finishCallback As Sub cdecl(param As Any Ptr ,job As wkeNetJob ,result As wkeLoadingResult)
End Type

下面是两个回调的实现,当然也必须要说cdecl导出类型的:

Sub wkeNetJobDataRecvCallback cdecl(ByVal param As Any Ptr ,ByVal job As wkeNetJob ,ByVal dataIn As Any Ptr ,ByVal length As Integer)Dim d As DownInfo Ptr = paramDim dataOut(length) As ByteCopyMemory(Varptr(dataOut(0)) ,dataIn ,length)Dim f As Integer = FreeFile()Open d->FileName For Binary As #fPut #f, LOF(f),dataOut()Close #fEnd SubSub wkeNetJobDataFinishCallback cdecl(ByVal param As Any Ptr ,ByVal job As wkeNetJob ,ByVal result As wkeLoadingResult)Dim d As DownInfo Ptr = paramIf MsgBox("是否需要打开文件?" ,"下载完成" ,MB_YESNO) = 6 ThenShellExecute Me.hWnd, "Open", d->FileName, "", "", 0End IfDelete d
End Sub

wkeNetJobDataRecvCallback负责文件字节流的接收;wkeNetJobDataFinishCallback负责下载完成的处理,例如打开。

wekDownload2事件的实现:

1、从disposition想办法获取下载的文件名字(不一定有)

2、如果没有,则从url的路径获取名字

3、引导用户选择保存的文件目录

4、如果本地存在同名文件,则自动删除

5、把两个回调的地址给接上去

6、事件函数返回1,表示开始接收

Function MainForm_Miniblink1_Download2(hWndForm As hWnd ,hWndControl As hWnd ,WebView As wkeWebView ,expectedContentLength As size_t ,url As CWSTR ,mime As CWSTR ,disposition As CWSTR ,job As wkeNetJob ,wkeNetJobDataBind As Any Ptr) As BOOL '页面下载事件。点击某些链接,触发下载会调用 Dim strFileName As String = ""If Len(disposition) > 0 ThenstrFileName = GetStrCenter(disposition ,"filename=""" ,"""")End IfDim nIndex As IntegerIf Len(strFileName) <= 0 ThennIndex = InStrRev(url ,"/")If nIndex > 0 ThenDim nQuery As Integer = InStr(nIndex ,url ,"?")If nQuery > 0 ThenstrFileName = Mid(url ,nIndex + 1 ,nQuery - nIndex - 1)ElsestrFileName = Mid(url, nIndex + 1)End IfEnd IfEnd IfDim strSaveFileName As String = FF_SaveFileDialog(hWndForm , "下载保存", strFileName, "", "所有的文件 (*.*)|*.*")If strSaveFileName = "" ThenFunction = 0Exit Function End IfnIndex = InStr(strSaveFileName ,"|")If nIndex > 0 ThenstrSaveFileName = Left(strSaveFileName, nIndex - 1)End IfIf FileExists(strSaveFileName) ThenIf MsgBox("文件已经存在,是否覆盖?" ,"文件覆盖提示" ,MB_YESNO) = 7 ThenFunction = 0 Exit FunctionEnd IfEnd IfStatic d As DownInfod.FileName = strSaveFileNamed.Length = expectedContentLengthd.Down = 0Static t As wkeNetJobDataBindt.param          = Varptr(d)t.finishCallback = @wkeNetJobDataFinishCallbackt.recvCallback   = @wkeNetJobDataRecvCallbackMoveMemory(wkeNetJobDataBind ,Varptr(t) ,Len(t))Function = 1
End Function

驰骋乾坤曰:

当然,vfb也可以不用动不动就MoveMemory,可以直接操作地址:

Dim t As wkeNetJobDataBind ptr = wkeNetJobDataBind
t->param          = Varptr(d)
t->finishCallback = @wkeNetJobDataFinishCallback
t->recvCallback   = @wkeNetJobDataRecvCallback

勇芳VFB的Miniblink组件实现文件下载相关推荐

  1. miniblink控件JS和本地函数互相调用VisualFreeBasic例题

    miniblink 作为一个小微浏览器内核,用来写软件的HTM前端界面,非常不错. VisualFreeBasic 已经将 miniblink 控件化,用户只需要拖个控件图标就可以使用了. 这里举例最 ...

  2. FreeBASIC编程IDE——VisualFreeBASIC简介

    VisualFreeBASIC(简称VFB)是之前FireFly的改进版本,用于FreeBASIC的可视化设计,是国内勇芳仿照FireFly样式设计的IDE.该IDE类似VB6语言集成开发环境.拥有和 ...

  3. 重力模拟,模拟了高达100000粒子和一个中心物体之间的基本引力

    VisualFreeBasic 中的简单重力模拟 代码模拟了高达100000粒子和一个中心物体之间的基本引力. 可以调整模拟速度. 可以调整粒子的初始速度 (方向角是随机的) 可以调整粒子质量 重置微 ...

  4. COM新手入门知识点汇总

    导读: COM组件:指实现某个功能集合的服务器,可以是dll.exe或者其它.一般用c++实现,也可用其  它语言实现,和语言无关.com组件可以存在于本地电脑,也可以存在于远程服务器中. COM注册 ...

  5. [数据结构]freebasic实现动态单链表

    前言 首先,感谢勇芳为我们提供了强大的编辑器vfb.这是我在csdn上第一次发关于freebasic的博客.因为我是一名初三学生,没有时间系统学习fb,以下代码有不规范的还请各位大佬指出[真诚] (转 ...

  6. visualfreebasic 5正式版

    visualfreebasic 5是基于FreeBasic编程语言开发的一款IDE工具,集成了IDE.编译器.帮助.函数库等,且承担了非常繁琐的核心操作,让用户只注重应用层面开发,轻轻松松进行编程,其 ...

  7. VisualFreeBasic编程教程(从零开始学或VB进阶)

    VisualFreeBasic 是 可视化 FreeBASIC 集成编程环境 现在我来带大家入门到美妙而神奇的编程世界! 为了能顺利使用 VisualFreeBasic ,必须了解以下内容 一.所有窗 ...

  8. Angular 文件上传与下载

    Angular文件上传与下载 文件上传 方式1 使用NG ZORRO中的组件. 文件下载 方式1 直接下载 方式2 通过HTTP请求后端数据的方式进行下载 文件上传 方式1 使用NG ZORRO中的组 ...

  9. AUTOSAR从入门到精通100讲(三十一)-AutoSar中RTE的生成准备

    用于软件组件的RTE生成器              图1  System Build Methodology 根据之前RTE的overview介绍可以知道,车辆功能的描述基于软件组件组合.软件组件原 ...

最新文章

  1. JDK 源码 Integer解读之一(toString)
  2. C# DateTimePicker控件如何精确设置显示时分秒
  3. Logistic Regression--逻辑回归算法汇总
  4. JavaScript四舍五入的改进
  5. 内存和swap查看 内存是拿来用的 不是看的
  6. c语言四字节转浮点数_C语言浮点书于字节互相转换
  7. linux匿名页 文件页,文件页和匿名页
  8. 使用log4j记录日志_使用log4j2免费分配日志记录
  9. 携程“线上摆摊”:1晚赚3105万
  10. mybatis No enum const class org.apache.ibatis.type.JdbcType.Date 坑爹的配置
  11. Jupyter Notebook——如何快速地以当前文件夹目录打开 Jupyter Notebook
  12. win10鼠标不受控制乱动_终于可以一键禁止Win10自动更新了
  13. Axure 9.0.0.3704 授权码
  14. 群体遗传进化专题之选择性清除分析
  15. 读书笔记《Effective C++》条款40:明智而审慎地使用多重继承
  16. c语言入门自学免费app,C语言入门学习最新版下载-C语言入门学习app手机版v1.0.2 安卓版-腾飞网...
  17. 【茗创科技】婴儿脑电机器学习实用指南
  18. 入门人工智能该读哪些书?五份AI经典书单
  19. Python OpenCV 自动生成快乐源泉小瓶子图片(OpenCV中文写字)
  20. LeetCode1710——卡车上的最大单元数

热门文章

  1. 大一 大数据Python实验报告汇总
  2. 近世代数 笔记与题型连载 第八章(置换群)
  3. Java编程思想读书笔记_第6章(访问权限)
  4. ubuntu安装QT5.7.1
  5. 如何有效开展小组教学_如何有效的开展小组合作,用小组合作活动推进教学——徐倩虹...
  6. android n模拟器,Android N预览模拟器崩溃
  7. 进攻:设备动作流程(二)
  8. [软件工具][windows]视频批量转图片工具使用教程
  9. VB6.0 url encode
  10. Android模拟器(ADM)打不开/data,无法导出数据库文件