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
tutorial:dlllibrary [2018/09/21 10:44]
admin
tutorial:dlllibrary [2019/03/15 10:42] (current)
admin
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 (จาก Example-1) ​เพื่อเก็บฟังก์ชั่นคำนวณหาพื้นที่หน้าตัดท่อ\\ 
-__ข้อสังเกต__:​ ..+__ข้อสังเกต__: ​ชื่อตัวแปร 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 (จาก Example-1) เพื่อเก็บฟังก์ชั่นคำนวณหาพื้นที่หน้าตัดท่อ\\
 +__ข้อสังเกต__:​ มีดังนี้ \\
 +  *จะต้องมี 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 ​ |
  
-จากตารางข้างบนอธิบายถึงความต่างของแต่ละ 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 ​มีทั้งเรทิศทางการใส่ค่าตัวแปร และการกำจัดค่าของตัวแปรใน Ram จะเห็นได้ว่า default, register และ pascal จะมีการใส่ค่าตัวแปรแบบ "​ซ้ายไปขวา"​ หรือ LTR (Left-to-Right) ในขณะที่ cdecl, interupt, safecall, stdcall และ oldfpccall จะใส่ค่าตัวแปรแบบ "​ขวาไปซ้าย"​ หรือ RTL (Right-to-Left) ​ 
-**__หมายเหตุ__** - \\ +\\ \\ 
-  *การไม่ระบุ Calling Convention นั้น จะหมายถึงการเรียกใช้งานแบบ default ซึ่งตัว ​default สำหรับ FPC คือ register+**__ข้อควรระวัง__** - หากเราระบุ 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>​
  
 \\ \\ \\ \\
tutorial/dlllibrary.1537501443.txt.gz · Last modified: 2018/09/21 10:44 by admin