编写dll时的内存分配策略
2024-10-19 04:27:05
前一篇文章介绍了为何要共用内存管理器,有人要问可不可以在编写dll时更通用一些,可以兼顾其它编译器(如果是其它编译器的话,Delphi写的dll不能与其它语言共用内存管理器),采用一定的策略来避免在dll内创建RTL自动管理的数据类型做参数或返回值,这样其它非Delphi的开发语言也可以用了!
完全可以!
一般的策略如下:
1.在主调函数中申请一块空间
2.把这个空间的地址传送给dll
3.dll内部进行逻辑运算,得到结果后把值添到主调函数传递过来的空间上
4.主调函数获取值,根据业务规则对空间进行处理(释放等操作)
在整个工作周期中,申请的内存一直掌握在主调函数的手中,没有给dll任何管理对象的机会!
看一下下面的主调函数申请内存的模板!
在这里需要强调几点:
//.不用共用内存管理器的话,数据类型需要使用Windows标准类型,如PChar!另外在dll中返回结构体时,最好结构体内的成员为基本数据类型,不要成员又是指针,一不小心就会出错!
//.PChar是一个指针,一般在主调函数中申请空间时先申请255,并把地址传入dll,dll进行逻辑处理,处理完毕后进行返回,返回时,长度可能远远小于255,所以在返回时通过一个变参告诉主调,实际只用了N个长度,这时主调在主动清理实际使用的长度!
//.一般在程序中string与PChar都是结合使用,即返回PChar后直接给一个string,这样更方便!但string类型的特殊性(与Java的string类似),直接赋值会出现问题,故需要用Move或CopyMemory进行内存复制工作,对于为什么出现问题,我想单独写一个文章来解释!
type
TGetStr=function(Src: PChar;srcLen: Integer;Buffer: PChar;var Size: Integer):boolean;stdcall; function GetDllStr: string;
var
DllHnd: THandle;
GetStr: TGetStr;
Str,Buf: PChar;
size:integer;
begin
size:=;
DllHnd := LoadLibrary(PChar('project1.dll'));
try
if (DllHnd <> ) then
begin
@GetStr :=GetProcAddress(DllHnd, 'TestFunc');
if (@GetStr<>nil) then
begin
GetMem(Str, size);{分配}
StrPCopy(Str,'asdf');
GetMem(Buf,Size);
try
GetStr(Str,size,buf,size);
result := StrPas(buf);{返回}
finally
FreeMem(Str);{释放}
FreeMem(Buf,Size);
end;
end
else
begin
application.MessageBox(PChar('DLL加载出错,DLL可能不存在!'), PChar('错误'),
MB_ICONWARNING or MB_OK);
end;
end;
finally
FreeLibrary(DllHnd);
end;
end; //dll实现
function AddStr(Src:PChar):string;
begin
result:=Src+'/Liangpei hello!';
end;
function TestFunc(Src: PChar;srcLen: Integer;Buffer: PChar;var Size: Integer):boolean;stdcall;//函数调用协议
var
LocalString:string;
begin
result:=false;
LocalString:=AddStr(Src);//一般字符串传入dll后,均要根据某些业务做一些加工或处理,AddStr就为处理函数
if (Buffer = Nil) or (Size < srcLen) then begin
SetLastError(Byte(Buffer <> Nil) * (*ERROR_MORE_DATA, need more buffer size*) );
Size := srcLen;
Exit;
end;
CopyMemory(Buffer,PChar(LocalString),Min(Size,Length(LocalString)));
Size := srcLen;
Result := true; end; exports
TestFunc;
最新文章
- 对JavaScript闭包和原型理解
- 【linux】su、sudo、sudo su、sudo -i的用法和区别
- Linux sed 批量替换多个文件中的字符串
- Java中String类的方法及说明
- MyBatis crud操作
- mac os x用macport安装redis
- 【py分析】使用SGMLParser分析淘宝html
- Python 字典(Dictionary) setdefault()方法
- 时序列数据库武斗大会之 TSDB 名录 Part 1
- linux 上不去网
- JavaScript的68个技巧一
- Windows Azure HDInsight 现已正式发布!
- Java String 类的 equals 和 ==
- List<;Object>;中,以Object的某一属性值为参照进行排序,选取最大记录的解决办法
- 对Java配置文件中敏感信息进行加解密的工具类
- SpringBoot2.0+Mybatis-Plus3.0+Druid1.1.10 一站式整合
- 游戏编程算法与技巧 Game Programming Algorithms and Techniques (Sanjay Madhav 著)
- 总结sql中in和as的用法
- 2018-2019-2 网络对抗技术 20165320 Exp4 恶意代码分析
- 手把手教你用CAB发布OCX的简单办法
热门文章
- 使用solr报错
- [转]Cross-type joins in Elasticsearch
- JavaScript中的内置对象-8--4.date对象中-获取,设置日期时间的方法; 获取,设置年月日时分秒及星期的方法;
- 20165228 2017-2018-2 《Java程序设计》第1周学习总结
- 【重要】NOI-1.2-10-字符串大小
- Unity射线检测的用法总结
- CSS3 transform变形(2D转换)
- acm 2072
- 网站基于vs,复选框,单选款
- 异构环境oracle数据库迁移dmp文件之exp和imp以及expdp和impdp