• 编写dll时的内存分配策略


    前一篇文章介绍了为何要共用内存管理器,有人要问可不可以在编写dll时更通用一些,可以兼顾其它编译器(如果是其它编译器的话,Delphi写的dll不能与其它语言共用内存管理器),采用一定的策略来避免在dll内创建RTL自动管理的数据类型做参数或返回值,这样其它非Delphi的开发语言也可以用了!

    完全可以!

    一般的策略如下:

    1.在主调函数中申请一块空间

    2.把这个空间的地址传送给dll

    3.dll内部进行逻辑运算,得到结果后把值添到主调函数传递过来的空间上

    4.主调函数获取值,根据业务规则对空间进行处理(释放等操作)

    在整个工作周期中,申请的内存一直掌握在主调函数的手中,没有给dll任何管理对象的机会!

    看一下下面的主调函数申请内存的模板!

    在这里需要强调几点:
    //1.不用共用内存管理器的话,数据类型需要使用Windows标准类型,如PChar!另外在dll中返回结构体时,最好结构体内的成员为基本数据类型,不要成员又是指针,一不小心就会出错!
    //2.PChar是一个指针,一般在主调函数中申请空间时先申请255,并把地址传入dll,dll进行逻辑处理,处理完毕后进行返回,返回时,长度可能远远小于255,所以在返回时通过一个变参告诉主调,实际只用了N个长度,这时主调在主动清理实际使用的长度!
    //3.一般在程序中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:=255;
      DllHnd := LoadLibrary(PChar('project1.dll'));
      try
        if (DllHnd <> 0) 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) * 234 (*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;
    View Code
  • 相关阅读:
    Android学习之Android studio TraceView和lint工具的使用具体解释
    Caffe + Ubuntu 15.04 + CUDA 7.0 安装以及配置
    web安全之渗透测试
    屏蔽alert弹框下面一层的操作
    org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session:
    java.lang.NoClassDefFoundError
    20 道 Spring Boot 面试题
    java节假日api--关于节假日想到的
    CSVWriter生成文件时writer.writeRecord();方法保存的文件末尾多一个空行
    git思维导图
  • 原文地址:https://www.cnblogs.com/key-ok/p/3358963.html
Copyright © 2020-2023  润新知