数学建模社区-数学中国

标题: [转帖]关于DLL创建和使用的问题 [打印本页]

作者: ilikenba    时间: 2004-6-11 22:20
标题: [转帖]关于DLL创建和使用的问题
先前在论坛上看了一下用BCB来写DLL的问题,我觉得讲的还不是很浅显
; J: S1 L0 F2 [+ g而且不够规范.有些地方,让人不明白. * B+ j9 f# }# X1 x+ H+ m
所以我自己私下翻了一些资料,把自己这几天的体会告诉大家.虽然示例代码不是BCB的,但是 + Z5 u7 t4 Z% k2 s
也可以说明一个思路.大家一定能够看得懂的. + x" X& A5 u% G. [/ Z
这里都是以VC6.0,来创建DLL文件的.代码示例都来自<<Windows程序设计>>第五版.是Win SDK写的
1 Z; ]' g5 W) n! r- |- c9 _没有使用任何VC方面的关键字~~没有使用MFC技术~而且很规范的方法~ 6 [* K7 g8 j" N; {' n$ F2 C0 J
建议大家应该学习这种一丝不苟的规范精神~~ ( ?- [: i- h' r  q6 R3 G
& z$ z" @, n8 A7 v$ `  W7 {9 A
一.动态连接库的创建
3 J1 l1 l% c2 ~: M; S2 i, }% ?# d: o! ^" m8 a9 O& d! ?
选择File->New,再选择Projects选择Win32 Dynamic-Link Library,然后在Project Name里输入
$ h  B$ V! r- Y- ~4 UMyFirstDll.
4 C  S# h# R+ i这样子就建立了一个DLL工程.接下来.
3 N7 x9 V: G; _9 t. b8 n1 Y选择File->New,Files选择C/C++ Header File. File项填入MyFirstDll.H
! _: R: [9 |) y' N1 ?4 c& W4 \这样就创建好了头文件.
# c4 _: [% N0 [, v选择File->New,Files选择 C++ Source File .File项填入MyFirstDll.C
9 n- b( X- v4 [4 l( B0 y# E! R" O5 L" g
开始写头文件.代码如下: + ^2 b  {: ?8 s
MyFirstDll.H
8 D, D6 L8 M3 x) e
0 G- S" |! }2 `( k/ k9 [<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>: m# P5 @9 N# l( c* O% v' l4 S9 o
$ F( D/ Z/ U, d" k6 Q% F4 K8 t: h
<TR>. s: U& Y  C6 i- `. u3 V6 B
<TD><B>代码:</B></TD></TR>
  \4 h# m8 k4 z, ?8 ~! N<TR>5 F* @6 F6 I8 W  V% _; G
<TD class=code>
( t) m0 k# @1 G! qifdef __cplusplus
3 U. T& l' S3 c" y" p  [#define EXPORT extern "C" __declspec (dllexport)
7 R! \/ `7 G! X# p* U7 ~3 Q4 q# i#else 9 k8 ^3 i! e) D1 ~2 H3 x. \$ v
#define EXPORT __declspec (dllexport)
1 d& g" y5 D) a/ Y$ d. ]#endif
2 O  L+ j9 D( H% e1 b7 R5 Q5 h7 ~9 K! @
EXPORT BOOL CALLBACK EdrCenterTextA (HDC, PRECT, PCSTR) ;
% c9 u1 r# o! s, ZEXPORT BOOL CALLBACK EdrCenterTextW (HDC, PRECT, PCWSTR) ;
- ]+ N3 ]+ l, c' E- h$ b% `. ^5 E& n3 t2 ]& H) q9 i! }. S. k* y
#ifdef UNICODE
) ^' K2 Z& O% u% m' c#define EdrCenterText EdrCenterTextW
. k, X) }! m# [' e#else
% a0 }/ C0 y3 l- v* Z#define EdrCenterText EdrCenterTextA
5 A& r& q  T1 ], b#endif
+ v2 k* h: Y: Q: T6 g</TD></TR></TABLE>1 ^+ {0 X8 O7 p# S% k
MyFirstDll.C ) [4 R4 ^0 f5 z& ?1 f

0 q( ?) z7 |: d+ T<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
  f7 H9 Q# W, s' x( V1 x. [
, N! i, a1 M5 D1 v8 \1 n<TR>3 b) `( ?+ B" K7 a+ n. A+ F( v
<TD><B>代码:</B></TD></TR>
* k6 p3 ^% l/ |3 G6 V( P" L<TR>) ~! E' B% l' t" b6 k& W; G" d
<TD class=code>
7 j- ~0 a9 e, J6 z* tinclude &lt;windows.h&gt; ' A: _5 v5 w) x, h  r  n
#include "edrlib.h"
- H9 r( n* [7 @* H6 T
; E+ q" ]) e% [) [8 aint WINAPI DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
& ?+ G# L6 j, i! l$ e: F) A+ q& c{
* v5 O1 L( ~/ P1 h( d, O     return TRUE ;
$ X7 v2 o! C% V}
8 e9 d" G" n$ C6 n8 h* m0 \4 }# Q3 y
EXPORT BOOL CALLBACK EdrCenterTextA (HDC hdc, PRECT prc, PCSTR pString)
8 S. @4 Q7 W% Q4 \) w- e. d' n{
0 g! Q' z  `+ P/ g; g, S     int  iLength ;
. ^- y/ v- X4 J4 R% t     SIZE size ; ) X7 x3 C( [" W0 k
# T6 C3 g" Y' U) z% c2 L3 q
     iLength = lstrlenA (pString) ; 5 y& b# q" B4 w$ {2 b3 z
: U5 ]# h( B3 X, i7 l
     GetTextExtentPoint32A (hdc, pString, iLength, &amp;size) ; * E5 V" h5 t5 {7 m2 m3 |2 n
" G9 \& B4 y0 L2 }0 W5 m
     return TextOutA (hdc, (prc-&gt;right - prc-&gt;left - size.cx) / 2, * t7 n3 U+ e) `4 ]4 @: n& F/ G
                           (prc-&gt;bottom - prc-&gt;top - size.cy) / 2,
+ M0 _1 V/ P; B  l; O. ^                      pString, iLength) ;
' U* l/ i* ]2 r( D: s$ J, N}
: ?# v, q. @7 P7 ~0 U, P8 ~6 y, H6 r; ^0 V
EXPORT BOOL CALLBACK EdrCenterTextW (HDC hdc, PRECT prc, PCWSTR pString) . ?3 Q: r6 r' u1 }: h4 k. u; Z
{
" p0 M. k. n+ b3 ?7 x     int  iLength ;
" c+ n% B+ |$ j# }" b% E     SIZE size ; ' \; H. f( D; q

, ?. Q$ C4 R$ W     iLength = lstrlenW (pString) ; # j' G  D1 s& ?( g5 `) e& b
) c/ A. k- [# ^5 ~& L5 X
     GetTextExtentPoint32W (hdc, pString, iLength, &amp;size) ; . Y& }& d- Q) r' D- [( s

- ^( @3 V& R8 H2 p     return TextOutW (hdc, (prc-&gt;right - prc-&gt;left - size.cx) / 2, ( L6 d0 v8 D( O$ z
                           (prc-&gt;bottom - prc-&gt;top - size.cy) / 2,
# j' S( I, a6 H. o                      pString, iLength) ;
: D# T$ k+ D) x# l0 e}
( ?# c1 Q7 h( E. h</TD></TR></TABLE>
- s  ?  Y8 g" Z; r$ U( k5 c' W
( @; K) K& Y9 L1 j! @
0 d8 s. q. x% T上面这两个文件创建完成.
3 M7 f; N$ X7 r3 L. H" Y7 T这两个文件中特殊之处,就是定义EXPORT标识标.其实在DLL中,应用程序使用的 , t) C/ _4 w' q/ [
函数必须是导出的.这样就确保函数名添加到MyFirstDll.Lib. 9 O( g0 n" x8 s! d9 \
EXPORT包括保存类说明__declspec(dllexport),当头文件按C++模块编译时附加的"C"
/ t! b( A9 b9 _7 Q  j! j以防止编译程序破坏C++的函数名.而且能够允许C和C++程序都能使用这个DLL ' ]( h. z6 k! m

0 k  f2 W5 |. M1 D8 G8 m6 E/ i! h" v7 x; [+ Y' }
当库首次启动和结束时,我们就需要调用DllMain函数.
1 C/ w: U  p" K. rDllMain的第一个参数是库的实例. ' }2 X0 b  S( p# {2 `& ~
DllMain的第二个参数fdwReason可以四个值之一,这四个值如下:   y( C4 \4 Y, W" ~* R
DLL_PROCESS_ATTACH :表示动态连接库被映射到一个进程的地址空间
8 \+ C& ~- S6 |9 v. [1 {! ?DLL_PROCESS_DETACH :意味着进程不再需要DLL,从而提供给库自己请除自己的机会 7 E1 [& l3 l  m
DLL_THREAD_ATTACH :某个进程创建了一个新的进程 / Z% [# \& g" w: B, u+ t  e
DLL_THREAD_DETACH :当使用这个调用DllMain时,线程仍然存在,这时线程可能在使用PostMessage前已经退出了. 3 p, i  N7 ]3 w% L, U2 |  O
; g1 R1 ?5 C/ B, e: S' Z  f9 F
编译上面的C++ Source File,得到一个MyFirstDll.dll. 6 ?& h0 V4 y( W5 B! i

/ o+ e# o/ `5 i* N% ^& b# `- E9 P+ u% ~# C, e, w: v
二.动态链接库的调用方法
# ]& N. C* N) J% A& _4 U. _9 n  ]: F1 O& P( J3 g9 A
下面来调用和测试这个DLL ; K) U; `6 O; s0 o$ h/ i
; ~1 Y: ]6 s$ @9 n, _
和正常情况一下,创建一个Win32 Application工程.
$ T! }3 P! e9 ?; x在调用Dll的时候,分两种调用,一种显示,一种是隐式. ) c0 ], b9 }% W$ f8 s
这里分别讲述. 2 V5 B2 n6 z$ ~6 ?  l5 C
在进行下面代码之前,请将MyFirstDll.h,MyFirstDll.dll,MyFirstDll.Lib复制到刚创建的工程目录. ) e4 A( m9 d* n$ i/ O  {5 h( M

2 a) c$ ]6 R# y, [* `" P5 N# D% f5 T9 V: g
隐式调用.其使用方法和使用Lib文件无区别.
$ n* u! d  @' P/ `) k  ^
% _4 O. a# }2 K! o$ B<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0># N6 y9 q: G6 r4 W8 g: b

% ?. x; n& @: [# o: B: A2 Z<TR>6 Q8 k' t1 Z% J
<TD><B>代码:</B></TD></TR>6 u  A+ W0 V! p2 G
<TR>/ d, ^# j( f) b2 }- Z
<TD class=code>  _' [3 M, k9 M, `! m8 r
#include &lt;windows.h&gt;
" Y/ h0 P# Y' F2 ]9 y) C2 d#include "MyFirstDll.h" ' `1 r( E9 ]0 E# p+ M0 m
" a( |$ w7 V3 T. E3 p) Y6 S' }
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
0 J$ B- m8 i: R( O/ X" x( D4 @; S) Q# v% }( B
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 2 v" w- M7 j0 m1 a' @% M4 H
                    PSTR szCmdLine, int iCmdShow) % T8 L' r3 {, h9 p2 S
{
& @, b3 Z2 ~( g9 c8 Y: F+ v/ H, X     static TCHAR szAppName[] = TEXT ("TestDll") ; * w. K/ w3 i# L3 K
     HWND         hwnd ;
" k. q  f& l8 H0 B& Q& x& d1 U     MSG          msg ; " G: [% h. T+ D! D/ o0 S  z' ?
     WNDCLASS     wndclass ; 1 q# l# k5 v- o

( c9 ^: e; g; P4 f/ h8 ]     wndclass.style         = CS_HREDRAW | CS_VREDRAW ; 5 ^2 A& E- i7 n6 `
     wndclass.lpfnWndProc   = WndProc ; ) y8 W3 O4 i$ i+ h! ~) F
     wndclass.cbClsExtra    = 0 ; - @) ?' }) B+ ]# K* R
     wndclass.cbWndExtra    = 0 ;
" [9 j4 p1 B5 N. f+ t* ~6 z     wndclass.hInstance     = hInstance ;
8 A6 h- [3 u5 \' a" L' ~5 W% A* [; y6 ?     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ; + {' v( j4 t4 [5 a' R9 F1 W
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
. v2 H) `- ]! X     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
4 |# q* h* c* A     wndclass.lpszMenuName  = NULL ; * J% W" e' c$ a- R3 r
     wndclass.lpszClassName = szAppName ;
% \( ?/ ?+ P1 h      
" H2 Q8 D5 m5 \* |9 z+ L8 b" H$ V. f     if (!RegisterClass (&amp;wndclass)) - S9 I4 o" R0 a9 t9 O& _4 @/ u, h
     {
2 L- G0 l/ `1 Z: q; N7 \          MessageBox (NULL, TEXT ("This program requires Windows NT!"), 4 Q! {; B- d1 ^: h- K4 Q- I
                      szAppName, MB_ICONERROR) ;
. B* ?0 Z+ t" c1 j$ @* ?4 i* c          return 0 ;
5 G# o# I  D% s$ `     }
9 ~7 E) Q# o5 p. W9 o8 K      % L3 e/ z* `% F3 ~, E$ |- [% q
     hwnd = CreateWindow (szAppName, TEXT ("DLL Demonstration Program"), ) s" l1 f. `9 p1 g
                          WS_OVERLAPPEDWINDOW,
/ b- k1 z" y! E) m! R' i* P6 @                          CW_USEDEFAULT, CW_USEDEFAULT, * N- A2 G) K4 A2 K4 h7 e" V
                          CW_USEDEFAULT, CW_USEDEFAULT,
& \" t$ O+ C# d& m  a8 h                          NULL, NULL, hInstance, NULL) ;
7 }8 j, ~) Z5 U$ V: k$ @$ v      
! k/ h$ b1 }* D' M& k     ShowWindow (hwnd, iCmdShow) ;
0 R! ?4 D: g" _9 m, l! o6 k     UpdateWindow (hwnd) ; ( a1 g8 c0 \' k, _9 U
      
( D/ p) C  Q% a/ K5 b     while (GetMessage (&amp;msg, NULL, 0, 0)) 4 c! P$ Q  x$ Z+ R* X
     {
; H# }( h& x" c+ j: y2 C" }          TranslateMessage (&amp;msg) ; - c& y, q7 b' p* j, K+ W( T
          DispatchMessage (&amp;msg) ;
* h' s8 {2 q7 l- e) D     }
4 f! }# R$ g; N% \% R     return msg.wParam ; ' L7 z7 p: n7 ]' i) T
} 2 O. b; E; ~8 u8 u

5 B/ c! B' ?+ {- G) ^: g6 MLRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) ) X1 t& q* p1 E& ~
{ ; [! I7 @) q; u4 j8 E
     HDC         hdc ;
  K- H6 F+ y! E     PAINTSTRUCT ps ;
% h; [' @7 f, G. V0 K     RECT        rect ;
3 P+ ^# ?" U/ C; G      ' b/ a; {! d" U0 Y2 K
     switch (message)
, q2 ?$ E# n5 q' S     { : |3 \$ _+ ^: V. C
     case WM_PAINT:
( [, Z5 m% I$ B9 Q          hdc = BeginPaint (hwnd, &amp;ps) ;
% J& e% M# a, N' _$ o* a2 L% W3 |: L          3 e/ l1 Q, F- I
          GetClientRect (hwnd, &amp;rect) ;
; y# G' T# X, t2 V         
! l' M0 X. m* j: M4 a9 S          EdrCenterText (hdc, &amp;rect,
. s; S- x. s0 i  ^( ]/ [! X5 D  ~* v) y                         TEXT ("This string was displayed by a DLL")) ;
6 A. r3 l0 v- v, Q# N; I) t          " V( v& W. y0 o( h7 L
          EndPaint (hwnd, &amp;ps) ;
: n# [' ?3 B& X, ^          return 0 ; 4 T! I9 Q+ w6 S# C- f0 t3 f% n5 {
         
0 z1 q9 O; f: [1 i; u% e: e     case WM_DESTROY: 6 p8 q* R( Q; S1 o
          PostQuitMessage (0) ; . L2 I* j7 l" P4 `5 l) Z
          return 0 ;
' j0 w. Z8 h; l0 T1 ^     } ; ^) ]/ ]0 \8 m# X/ W/ ^
     return DefWindowProc (hwnd, message, wParam, lParam) ;
" A$ D2 K. t7 v} 6 ^; K# Y& o' }2 o1 Z  d
</TD></TR></TABLE>. ~/ [+ U! H- W0 U! Z$ a/ |
那么显示调用又是怎么回事. 5 z* M0 e! Y: f! R: G. z
大家看下面.
+ i; ^- e3 \0 K5 M- p" o1 x( f
7 O6 _& W  e  X: F# h) r6 ~<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>5 M/ t: Y& r, k  U! P
: D& i3 @& U0 V
<TR>
9 K+ U. L% N; t0 n6 g<TD><B>代码:</B></TD></TR>% ^6 q1 e% e# M% J' x* \5 K) i
<TR>$ n6 g; g/ y( d. N: H
<TD class=code>
* ~6 Y4 m* S- @  m* r4 |% Etypedef BOOL (WINAPI* MyEdrCenterText)(HDC,PRECT,PCWSTR);
- r* p  F' {: j( y) \HANDLE hLibrary;
' R# I0 D0 ^* }6 m% r0 Y8 n3 P  XMyEdrCenterText myEdrCenterText; ! J; l7 i0 f$ H
% M/ _8 f0 q% @4 I$ o6 x( ]
hLibrary = LoadLibrary(TEXT("MyFirstDll.Dll");
1 V* R/ g  O& Q* [9 q- fmyEdrCenterText=(MyEdrCenterText)GetProcAddress(hLibrary,TEXT("EdrCenterText));
0 \$ h* Q2 c& t1 q- f  l( I" amyEdrCenterText(hdc,&amp;rect,TEXT("你的话"));
3 _$ g, q1 R* i" `: x+ D4 U$ }) c9 L5 T) v- P* s
FreeLibrary(hLibrary); 5 V. {' {* T* |
</TD></TR></TABLE>5 f4 W0 Q6 b2 v

& \2 o  u+ \( q! D, |# g+ D8 e这种调用不需要头文件.但是保存DLL在系统目录或在当前目录里.
' g; C  o7 u7 {7 M. T$ y
7 {, w# B5 v% `3 x
5 b1 W" [/ l2 h! |  D
# d0 [8 w1 U: j: n; W) L# B上面的示例都是Win32示例.不涉入VC的关键字.可以移植到BCB下,
( P$ E! a+ D* m; I4 x8 r+ a2 }在BCB下建议用一种规范化格式来创建并使用DLL. 1 D5 `' [7 b8 U9 [; n) T; x/ P
- g( n. j+ a/ Z' ^1 q' Q- T2 `
我感觉VC在这方面走的比较前,也比较规范~
* r' t( r1 H( h: g) t! V
+ N1 s+ d' y( G9 ^6 a以上示例采自&lt;&lt;Windows 程序设计&gt;&gt;第五版.




欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5