User Tools

Site Tools


tutorial:dlllibrary

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Last revision Both sides next revision
tutorial:dlllibrary [2018/09/21 10:32]
admin
tutorial:dlllibrary [2019/01/04 12:04]
admin [การระบุ Calling Convention]
Line 8: Line 8:
 |  Linux  |  .so  | |  Linux  |  .so  |
 |  MacOS X  |  .dylib ​ |  |  MacOS X  |  .dylib ​ | 
-\\ \\+\\ 
 =====การสร้าง Shared Library===== =====การสร้าง Shared Library=====
 ใน Lazarus IDE เราสามารถสร้าง Shared Library ไว้ใช้งานสำหรับ Window, Linux และ MacOS X ได้ทั้งหมดครับ โดยการเลือกเมนู \\ ใน Lazarus IDE เราสามารถสร้าง Shared Library ไว้ใช้งานสำหรับ Window, Linux และ MacOS X ได้ทั้งหมดครับ โดยการเลือกเมนู \\
Line 37: Line 37:
 end; end;
  
-exports ​FunctionName1;+exports ​FunctionName;
  
 begin begin
Line 47: Line 47:
   Run >> Compile   Run >> Compile
  
-เมื่อทำการ compile เสร็จเรียบร้อย เราจะได้ไฟล์ .dll ที่พร้อมใช้งานครับ ​+เมื่อทำการ compile เสร็จเรียบร้อย เราจะได้ไฟล์ .dll ที่พร้อมใช้งานครับ ​ให้นำไฟล์ .dll ไปไว้ใน folder เดียวกับไฟล์ Project เราได้เลย
  
 <hidden Example-1: Create .dll Library> <hidden Example-1: Create .dll Library>
Line 59: Line 59:
   SysUtils, Classes, Math;   SysUtils, Classes, Math;
  
-function PipeArea1(const DOut,​DIn ​ : double) : double;+function PipeArea1(const DOut,​DIn ​ : double) : double; ​{Calling;}
 begin begin
   result := (PI/​4)*(DOut*DOut - DIn*DIn);   result := (PI/​4)*(DOut*DOut - DIn*DIn);
 end; end;
  
-function PipeArea2(const DOut,​tw ​ : double) : double; ​+function PipeArea2(const DOut,​tw ​ : double) : double; ​{Calling;​} ​
 begin begin
   result := (PI/​4)*(DOut*DOut - (DOut-2*tw)*(DOut-2*tw));​   result := (PI/​4)*(DOut*DOut - (DOut-2*tw)*(DOut-2*tw));​
 end; end;
  
-exports PipeArea1, +exports PipeArea1,​PipeArea2;​
-PipeArea2;+
  
 begin begin
Line 80: Line 79:
 =====การเรียกใช้งาน Shared Library===== =====การเรียกใช้งาน Shared Library=====
 การเรียกใช้งาน Shared Library สามารถเรียกได้ 2 แบบ ดังนี้ การเรียกใช้งาน Shared Library สามารถเรียกได้ 2 แบบ ดังนี้
-  *Static Calling คือการเรียกในขณะ Compile-time นั่นหมายถึงเวลาที่เราำไฟล์ .exe ไปแจ่ายนั้น ไมจำเป็นตองบไฟล์ .dll ไปใน Folder ​นื่องจาก code ต่างๆใน Shared Library ได้ถูก compiled ไว้ใไฟล์ ​.exe เรียบรอยแว วิธีเรียกแบบนี้ีข้อดีคือไม่ซัซ้อน แต่มีข้อเสียคือจะทำให้ไฟล์ของโปรแกรมที่เราเขียนขึ้น ​มีขนาดใหญ่ +  *Static Calling คือการเรียกทุก function จก Library ​มาเก็บไ้ใแกรมหลักตั้งแตต้น ยกัวย่าง เช่น เราต้องการใช้น function ทั้งหมด 5 ตัว ทุกครังที่มีารรัน .exe function ทัง 5 ตัวดังก่าว ก็จะถูกเรียกมาเก็นโปรแกรมเราตั้งแต่ต้น  
-  *Dynamic Calling คือการเรียกใช้ ​ในขณะ Run-time นั่นคือเวลาที่เรานำไฟล์ .exe ไปแกจ่ยนั้น จำเป็นต้องแนบไฟล์ .dll ไปใน Folder ทุครั้ง ​เพาะตัว ​Shared Library ไมได้ถูก ​Compiled ​เขากับฟล์ .exe ังนันจึงถูกเรียกมาใช้เฉพาะน้แทน ​วิธีเรียกแบบนี้จะต้องเขียน ​code ที่ค่อนข้าุ่ก แตอดคืจะทำห้ขนาดของโปรแกรเราไม่ใญ่มากและรายังสามารถ Update ​ไฟล์ .dll ได้นภยหลัง+  *Dynamic Calling คือการเรียกใช้ ​function ​จาก ​Library ​พาะตัวที่ถูกใช้งานจิง ไได้เรียกมาใช้ทั้งมดแต่แรก อย่งไรก็ตาม ​วิธีนี้จะยุ่งยากกว่าวิธีแรกพอสมควร เพราะต้องเขียน ​procedure/​function ​นมเป็นพิเศษเพื่อเรีกใช้งาน function เหลานันทละตัว ขครของมัน\\ 
 +หมาหตุ: ทงสองแบบ ต้องการไฟล์ .dll แนบช้งนกับไฟ์ .exe ด้วยทุกครง 
  
 <hidden Example-2: Static Calling .dll Library> <hidden Example-2: Static Calling .dll Library>
 **ตัวอย่าง** การเรียก Library ชื่อว่า Pipe เพื่อเก็บฟังก์ชั่นคำนวณหาพื้นที่หน้าตัดท่อ\\ **ตัวอย่าง** การเรียก Library ชื่อว่า Pipe เพื่อเก็บฟังก์ชั่นคำนวณหาพื้นที่หน้าตัดท่อ\\
-__ข้อสังเกต__:​ ..+__ข้อสังเกต__: ​ชื่อตัวแปร Argument ของในโปรแกรมนี้ ไม่ตรงกับใน ​.dll \\ 
 +  *ไฟล์นี้ ใช้ PipeArea1(const D,​Di:​double):​double \\ 
 +  *แต่ในไฟล์ ​.dll ใช้ PipeArea1(const DOut,​DIn ​ : double) : double; \\ 
 +จะเห็นว่าชื่อตัวแปรสามารถตั้งให้ต่างกันได้ เพียงแต่ต้องเป็นชนิดเดียวกัน
 <sxh delphi;> <sxh delphi;>
 program StaticCalling_PIPEDLL;​ program StaticCalling_PIPEDLL;​
Line 96: Line 99:
   Classes;   Classes;
  
-function PipeArea1(const D,​Di:​double):​double;​ external '​Pipe.dll';​ +function PipeArea1(const D,​Di:​double):​double;​{calling;​} ​external '​Pipe.dll';​ 
-function PipeArea2(const D,​t:​double):​double;​ external '​Pipe.dll';​+function PipeArea2(const D,​t:​double):​double;​{calling;​} ​external '​Pipe.dll';​
  
 Var D,​Di,​t:​double;​ Var D,​Di,​t:​double;​
Line 110: Line 113:
   readln;   readln;
  
 +end. 
 +</​sxh> ​    
 +</​hidden>​
 +
 +<hidden Example-3: Dynamic Calling .dll Library>
 +**ตัวอย่าง** การเรียก Library ชื่อว่า Pipe เพื่อเก็บฟังก์ชั่นคำนวณหาพื้นที่หน้าตัดท่อ\\
 +__ข้อสังเกต__:​ มีดังนี้ \\
 +  *จะต้องมี unit ชื่อ Dynlibs\\
 +  *จะต้องมีการเรียกใช้ function เป็นตัวแปร หรือที่เรียกว่า Procedural Type \\
 +<sxh delphi;​highlight:​ [8,​13-14,​20-35,​42]>​
 +program DynamicCalling_PIPEDLL;​
 +//This example demonstrates the simple use of static/​Dynamic calling.
 +//For calling convention, register is used by default.
 +
 +{$mode objfpc}{$H+}
 +
 +uses
 +  Classes,​Dynlibs;​
 +
 +function PipeArea1(const D,​Di:​double):​double;​{calling;​} external '​Pipe.dll';​
 +
 +//Define procedural type for Dynamic Calling
 +type
 +  TMyDLL = function(const D,​Di:​double):​double;​{calling;​}
 +
 +
 +
 +Var D,​Di:​double;​
 +
 +  function CallDLib(const D,​Di:​double):​double;​
 +  var
 +    MyHandle: TLibHandle;
 +    MyDLLFunc: TMyDLL;
 +  begin
 +    MyHandle := SafeLoadLibrary('​Pipe.dll'​);​
 +    if MyHandle<>​0 then
 +      begin
 +        MyDLLFunc := TMyDLL(GetProcedureAddress(MyHandle,'​PipeArea1'​));​
 +        if Assigned(MyDLLFunc) then
 +          result:​=MyDLLFunc(D,​Di);​
 +      end
 +    else
 +      result:=10;
 +    FreeLibrary(MyHandle);​
 +  end;
 +
 +begin
 +  writeln('​Example for calling .dll library named Pipe.dll'​);​
 +  D:=0.25;
 +  Di:=0.23;
 +  writeln('​Static Calling PipeArea1(D,​Di):​ ',​PipeArea1(D,​Di));​
 +  writeln('​Dynamic Calling PipeArea1(D,​Di):​ ',​CallDLib(D,​Di));​
 +  readln;
 end.  end. 
 </​sxh> ​     </​sxh> ​    
Line 127: Line 183:
 |  oldfpccall ​ |  RTR  |  Callee ​ | |  oldfpccall ​ |  RTR  |  Callee ​ |
  
-แต่สำหรับ่ระบุนั้น ​compiler ​ะรู้ได้อง่าเราำลังใช้แบบ default ซึ่งนที่น้ก็คือ register+จากตารางข้างบนอธิบายถึงความต่างของแต่ละ Calling Convention มีทั้งเรื่องทิศทางการใ่ค่าตัวแปร และการกจัดค่าของตัวแปรใน Ram จะเ็นได้ว่า default, register และ pascal จะมีกาใส่ค่าตวแปรแบ "​ซ้ปขวา"​ หรือ LTR (Left-to-Right) ในขณะที่ cdecl, interupt, safecall, stdcall และ oldfpccall จะใส่ค่าตัวแปรแบบ "​ขวาไปซ้าย"​ หรือ RTL (Right-to-Left)  
 +\\ \\ 
 +**__ข้อควรระวัง__** - หากเราระบุ ​Calling Convention ใน .dll ไม่ตรงกบการเรียกใชไฟล์ .exe ก็อาทำใหเกิดการใส่ตัวแปรในแต่ละ Argument ของ Procedure/​Function สลับกันได้ ​จะนำไปสู่การคำนวณที่ผิดพลาดย่าแนนอน  
 +\\ \\ 
 +**__หมหตุ__** - ารไม่ระบุ Calling Convention น้น จะหมายถึการเรียกใช้งานแบบ default ซึ่ง ​default calling convention สำหรับ FPC คือ register 
 +<hidden Example-4: Static Calling .dll Library using stdcall as calling convention>​ 
 +**ตัวอย่าง** การเรียก Library ชื่อว่า Pipe เพื่อเก็บฟังก์ชั่นคำนวณหาพื้นที่น้าตัดท่อ\\ 
 +__ข้อสังเต__: เราจะใช้ Calling ที่ชว่า stdcall ซึ่งจะต้องมีการระบุ Calling Convention ทั้งใน .dll และโปรแกรมหลัก \\ 
 + 
 +<sxh delphi;​highlight:​ [8,​13]>​ 
 +library Pipe; 
 + 
 +{$mode objfpc}{$H+} 
 + 
 +uses 
 +  SysUtils, Classes, Math; 
 + 
 +function PipeArea1(const DOut,​DIn ​ : double) : double; stdcall; 
 +begin 
 +  result := (PI/​4)*(DOut*DOut - DIn*DIn); 
 +end; 
 + 
 +function PipeArea2(const DOut,​tw ​ : double) : double; stdcall; 
 +begin 
 +  result := (PI/​4)*(DOut*DOut - (DOut-2*tw)*(DOut-2*tw));​ 
 +end; 
 + 
 +exports PipeArea1,​ 
 +PipeArea2;​ 
 + 
 +begin 
 +end. 
 +</​sxh> ​    
 + 
 +<sxh delphi;​highlight:​ [10-11]>​ 
 +program StaticCalling_PIPEDLL;​ 
 +//This example demonstrates the simple use of static calling .dll library. 
 +//For calling convention, ​register ​is used by default. 
 + 
 +{$mode objfpc}{$H+} 
 + 
 +uses 
 +  Classes; 
 + 
 +function PipeArea1(const D,​Di:​double):​double;​ stdcall; external '​Pipe.dll';​ 
 +function PipeArea2(const D,​t:​double):​double;​ stdcall; external '​Pipe.dll';​ 
 + 
 +Var D,​Di,​t:​double;​ 
 + 
 +begin 
 +  writeln('​Example for calling .dll library named Pipe.dll'​);​ 
 +  D:=0.25; 
 +  Di:=0.23; 
 +  t:=0.013; 
 +  writeln('​Calling PipeArea1(D,​Di):​ ',​PipeArea1(D,​Di));​ 
 +  writeln('​Calling PipeArea2(D,​t):​ ',​PipeArea2(D,​t));​ 
 +  readln; 
 + 
 +end.  
 +</​sxh> ​     
 +</​hidden>​ 
 \\ \\ \\ \\
 =====References===== =====References=====
 https://​www.freepascal.org/​docs-html/​prog/​progsu7.html \\ https://​www.freepascal.org/​docs-html/​prog/​progsu7.html \\
 https://​www.freepascal.org/​docs-html/​prog/​progse22.html#​x173-1760006.3 https://​www.freepascal.org/​docs-html/​prog/​progse22.html#​x173-1760006.3
tutorial/dlllibrary.txt · Last modified: 2019/03/15 10:42 by admin