aardio内嵌资源的代码写法-以内嵌DLL为例

编写程序经常需要调用一些dll文件。大体有把dll内嵌进exe文件和不内嵌直接从硬盘调用两种方式。如果不内嵌,写起来相对简单,就写dll的绝对路径或者以exe文件为基础的相对路径就可以了。重点分析一下内嵌方式,当然这种方式其实并不局限于dll,其他文件也是类似的。

(一)使用$包含操作符进行内嵌

使用包含操作符就是在dll路径字符串前引号前面加上一个$符号,就可以了。编译的时候,程序会将dll以二进制方式嵌入exe。执行的时候,执行到这里,程序会从exe中提取这个二进制数据到内存,然后调用它。也就是说,程序执行的时候,已经不需要原来的dll文件了。这就是内嵌的目的,打包。写法就是:raw.loadDll($"dll路径")。一般来说,你从硬盘拖一个dll文件进代码,就会生成这种格式。

注意,上面的dll路径可以是任何路径,绝对路径、相对路径都可以,工程里面、工程外面无所谓,但是最好不要放在资源目录。因为资源目录是下面要讲的另一种内嵌方式,两种方式都用就会内嵌两次,平白无故的增加软件体积。例子:

import win.ui;
/*DSG{{*/
var winform = win.form(text="aardio form";right=360;bottom=247)
winform.add()
/*}}*/
var dll=raw.loadDll($"C:\Users\NIE\Desktop\basic.dll",,"cdecl")
dll.msgboxW("aardio成功调用vfb编译的dll")
winform.show();
win.loopMessage();

aardio内嵌资源的代码写法-以内嵌DLL为例_第1张图片

这个dll是16k,这个程序编译完是1083k,如果放进资源目录,编译完是1099k,证明确实是重复嵌入了一次。

 (二)放入res资源目录进行内嵌

放进资源目录的所有文件,默认都是内嵌的。所以不必再用$包含操作符,按理说直接写就行了,例如raw.loadDll("\res\basic.dll")。这样编译完成后,也是一样脱离了原来的dll。但是实际上不一定行,往往是开发环境可以,编译完成报错:

aardio内嵌资源的代码写法-以内嵌DLL为例_第2张图片

 今天就有一位群友遇到了这样的问题。这时当然可以把res目录复制到exe目录解决这个问题,但这就不是内嵌了。

我分析是这样,大多函数都支持直接使用内嵌资源,但是并不是所有的函数都如此,这个raw.loadDll函数只支持dll路径、内存数据(参考智能提示),并不支持直接使用内嵌资源。所以我们需要把内嵌资源转换为内存数据。可用的函数不止一个,一般使用string.load就可以,因为string.load是支持读取内嵌资源的(参考智能提示)。最后,可行的写法应该是raw.loadDll(string.load("\res\basic.dll"))

import win.ui;
/*DSG{{*/
var winform = win.form(text="aardio form";right=360;bottom=247)
winform.add()
/*}}*/
var dll=raw.loadDll(string.load("\res\basic.dll"),,"cdecl")
dll.msgboxW("aardio成功调用vfb编译的dll")
winform.show();
win.loopMessage();

aardio内嵌资源的代码写法-以内嵌DLL为例_第3张图片

 这样在开发环境和编译后都可以运行,编译完大小也是1083k。

 (三)内嵌后释放到硬盘

有些dll并不支持内存加载,编译时内嵌了,执行时还要释放出来。释放方法很多,这里只说常用的两种方法:

1.fsys.res扩展库,适用于内嵌资源文件释放。

import win.ui;
/*DSG{{*/
var winform = win.form(text="aardio form";right=360;bottom=247)
winform.add()
/*}}*/
import fsys.res
if not _STUDIO_INVOKED fsys.res.saveRes()
var dll=raw.loadDll("\res\basic.dll",,"cdecl")
dll.msgboxW("aardio成功调用vfb编译的dll")
winform.show();
win.loopMessage();

这样的话,exe运行时会在同一目录下生成res目录,dll文件就在其中,实际是从硬盘调用,也就不必string.load了。

aardio内嵌资源的代码写法-以内嵌DLL为例_第4张图片

2. io.appdata函数,通常用于$包含操作符内嵌文件的释放。

import win.ui;
/*DSG{{*/
var winform = win.form(text="aardio form";right=360;bottom=247)
winform.add()
/*}}*/
var dllpath=io.appData("aardio\basic.dll",$"C:\Users\NIE\Desktop\basic.dll")
var dll=raw.loadDll(dllpath,,"cdecl")
dll.msgboxW("aardio成功调用vfb编译的dll")
winform.show();
win.loopMessage();

aardio内嵌资源的代码写法-以内嵌DLL为例_第5张图片

 这样exe运行时会把文件释放在appdata目录,然后再从这里调用。

附录:上述测试用的basic.dll的生成代码(也是aardio编译的)

import console;
var basic  = /***
#define UNICODE 
#include "windows.bi"
Extern "C"  
   Function msgbox(byval s as LPCWSTR) As long Export 
     	MessageBox(0,s,"",0) 
     	return 1
   End Function
End Extern
***/
string.save("\basic.bas", basic)
import process.freeBasic;
process.freeBasic.dll("\basic.bas").wait()
console.logPause("已生成DLL,按任意键退出");
io.remove("\libbasic.dll.a");

你可能感兴趣的:(aardio,开发语言,经验分享)