数学建模社区-数学中国

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

作者: ilikenba    时间: 2004-6-11 22:20
标题: [转帖]关于DLL创建和使用的问题
先前在论坛上看了一下用BCB来写DLL的问题,我觉得讲的还不是很浅显
/ C' S; U4 [0 E; `而且不够规范.有些地方,让人不明白.
; B4 `- X) g% }: W$ |  [所以我自己私下翻了一些资料,把自己这几天的体会告诉大家.虽然示例代码不是BCB的,但是 6 o6 M( k' k, ]& `; P/ s( d+ b
也可以说明一个思路.大家一定能够看得懂的.
- B2 o0 m# J# w7 |# D% N! ^这里都是以VC6.0,来创建DLL文件的.代码示例都来自<<Windows程序设计>>第五版.是Win SDK写的
5 ?7 l* f; @0 E! M' y& @: L没有使用任何VC方面的关键字~~没有使用MFC技术~而且很规范的方法~
3 x5 f2 J4 {8 a建议大家应该学习这种一丝不苟的规范精神~~
2 v& h# d5 ?- {8 j& H9 V! U+ |. X, x0 H# Y$ l$ W
一.动态连接库的创建 ! I+ s& |0 L  `" Y. u( e5 y9 ^

( o6 |3 Q3 M! N+ M2 C: L选择File->New,再选择Projects选择Win32 Dynamic-Link Library,然后在Project Name里输入   R3 Y+ l3 H) _
MyFirstDll. + n. S# I# Y+ d- f+ L
这样子就建立了一个DLL工程.接下来.
4 x& c, W& E6 X. K9 D! U7 a' ?选择File->New,Files选择C/C++ Header File. File项填入MyFirstDll.H
9 ^. O; L3 B# \: f; t( x这样就创建好了头文件.
/ r9 E" A- s8 A% c3 l选择File->New,Files选择 C++ Source File .File项填入MyFirstDll.C
) u% E+ u# S! X" N; F2 s8 X2 C! K2 t9 F5 J
开始写头文件.代码如下: 5 D" {7 P7 X" }; w
MyFirstDll.H
7 \' u( A' A5 ~. i$ m
0 L6 o9 s  C* Z9 z<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>, T# ?1 a+ X6 v6 Y
+ w4 _# y3 O: ^
<TR>" ]) m9 P1 q  t6 X( ~
<TD><B>代码:</B></TD></TR>. j: O& i, u+ f+ L4 G
<TR>3 J# k' u& V: N" L( n! I
<TD class=code>2 v. L2 R* w' l  [5 P8 Q
ifdef __cplusplus $ o5 A. I: G1 t) F
#define EXPORT extern "C" __declspec (dllexport) 9 `# y2 n) W) K
#else
) i) J$ N3 |* h0 G1 h7 N+ I, B! S#define EXPORT __declspec (dllexport) , m9 s: V; q- A8 R+ Z2 N2 A
#endif ( S! ?+ a; w! H+ H
0 X  @- F: }% O4 h
EXPORT BOOL CALLBACK EdrCenterTextA (HDC, PRECT, PCSTR) ; ) r( F( G5 S4 |2 q5 i
EXPORT BOOL CALLBACK EdrCenterTextW (HDC, PRECT, PCWSTR) ;
% g# b0 m' a" |  O! x6 C
. T( j+ v. R* K* ^( G#ifdef UNICODE ; q1 L( L$ {& ]$ L
#define EdrCenterText EdrCenterTextW
1 G5 }' N5 X2 c#else
7 C! K: b: W1 @: {3 M6 M% r1 v#define EdrCenterText EdrCenterTextA
  n( O! ?+ C8 n, I( V- g  @#endif
/ K, T0 F* M' C3 `& }+ x</TD></TR></TABLE>
3 m* t6 T0 {* f4 ?0 fMyFirstDll.C
1 K! S) G9 H. b. w# Z, e. y7 W; l: o( b) J/ N0 l2 x
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
( w% \, q8 K7 D- S7 Q! S! m) ^* E  E' @6 O
<TR>
8 R; J- D1 O) l9 p<TD><B>代码:</B></TD></TR>4 ~8 I& c) l# ^4 G3 X4 d. E
<TR>9 B4 s- k8 G. U7 H( @& G
<TD class=code>
+ O' R5 m6 ]' F2 m+ j! w* o1 |include &lt;windows.h&gt;
9 ^$ c& K; }& C/ a* p#include "edrlib.h"
7 v3 B8 S+ Y& x5 \) H9 e
. |0 n* X- L2 f: Fint WINAPI DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) : i+ e" Z" u8 k0 {3 U% q1 T* h
{
/ x) w) Y- G; `) ^* K& P) S     return TRUE ;
& _' d4 S8 ]% j8 f0 D}
4 e! p$ B1 f" U, h- Z
) w9 N' l: t. O6 u4 x% XEXPORT BOOL CALLBACK EdrCenterTextA (HDC hdc, PRECT prc, PCSTR pString) . N- P& \: f% w, G! q& o
{
9 O* O- A  _2 Y9 s: a$ x9 o) y     int  iLength ;
* S: }3 d$ D! v. O) H5 K+ T     SIZE size ; # j( m+ A( Y, k6 n# T; U
& n; u$ u5 `9 {( X7 f8 s* a
     iLength = lstrlenA (pString) ;
, |' ^0 C  N' |- e& {2 N6 }+ V  S' f! ?* _( b5 }
     GetTextExtentPoint32A (hdc, pString, iLength, &amp;size) ; . M, o6 S1 p0 Z+ i2 T
2 `4 K' }0 x  t- x
     return TextOutA (hdc, (prc-&gt;right - prc-&gt;left - size.cx) / 2,
" a1 L. F- J  {" {7 h                           (prc-&gt;bottom - prc-&gt;top - size.cy) / 2, 7 m, a# h' \6 N: x7 C8 k$ |2 C5 o1 o
                      pString, iLength) ;
' P# D4 f# n; ?  w4 }  z0 T; m}
  D7 y) q" T/ x
; h4 U5 l1 ^  l% BEXPORT BOOL CALLBACK EdrCenterTextW (HDC hdc, PRECT prc, PCWSTR pString)
& C( a9 Q4 ]8 U8 [{ ! a* _$ R" o5 A
     int  iLength ; 3 z/ R: S2 c, F/ z! K
     SIZE size ; / F$ @, h: O* V( {5 L  H( O% z

; S1 H( ~4 ]3 y7 o     iLength = lstrlenW (pString) ;
6 ~' y6 ^, b  h/ M/ w# _( W3 S  n* D
     GetTextExtentPoint32W (hdc, pString, iLength, &amp;size) ;
. z/ s5 Z0 E8 }. T$ P8 T3 M  x, l# y/ x+ Y7 T7 t
     return TextOutW (hdc, (prc-&gt;right - prc-&gt;left - size.cx) / 2, 8 N  X& H0 c5 I0 N
                           (prc-&gt;bottom - prc-&gt;top - size.cy) / 2,
% F# }+ S# J0 L, K7 S! b1 y) v                      pString, iLength) ;
, C4 @5 O8 R# G$ y8 A  V  D} 7 K: m, E0 B/ e! V3 Y
</TD></TR></TABLE>5 m# [4 B6 `9 U: ?2 W/ U4 y

  A5 z" q& G# I4 K7 G( j8 ?9 m( D3 A
上面这两个文件创建完成.
$ D: t: E0 O9 m, O' ~% Q" u+ }) m这两个文件中特殊之处,就是定义EXPORT标识标.其实在DLL中,应用程序使用的 + d' p, n# S5 K6 W7 R
函数必须是导出的.这样就确保函数名添加到MyFirstDll.Lib. - X$ H7 [/ j$ ]7 S: f. Q  l
EXPORT包括保存类说明__declspec(dllexport),当头文件按C++模块编译时附加的"C"
- G% @! I3 I+ v. L以防止编译程序破坏C++的函数名.而且能够允许C和C++程序都能使用这个DLL
$ c- r# S- i4 f; h# k, Z9 S7 c$ b
: |! l/ T& e0 F; S
, K3 t" v" K3 z+ z6 i当库首次启动和结束时,我们就需要调用DllMain函数.
; V4 s' M) A6 r, [: e4 v5 jDllMain的第一个参数是库的实例. . }0 e3 y- w2 t& ?6 ]4 ]
DllMain的第二个参数fdwReason可以四个值之一,这四个值如下:
6 R$ `; B& H8 F% D3 c; {DLL_PROCESS_ATTACH :表示动态连接库被映射到一个进程的地址空间 $ n1 R- C) ~% _% S& O. R
DLL_PROCESS_DETACH :意味着进程不再需要DLL,从而提供给库自己请除自己的机会 8 [1 G/ N1 j* k+ X
DLL_THREAD_ATTACH :某个进程创建了一个新的进程 ( X4 W3 E1 P" a: [2 a4 ?
DLL_THREAD_DETACH :当使用这个调用DllMain时,线程仍然存在,这时线程可能在使用PostMessage前已经退出了. ; U5 _) e# @- c- ]9 e

4 K" }6 {9 J3 S9 D编译上面的C++ Source File,得到一个MyFirstDll.dll. * ^4 W# M) e) q% k4 g9 M$ L& P; Y

7 I4 r% U$ p0 _7 n% P
4 b- X3 t2 o# G二.动态链接库的调用方法
. t+ w  a0 Z7 d" X9 y1 v" ]  G0 x/ B
) {, T$ u, ]7 O4 @下面来调用和测试这个DLL
9 K& ^% l$ }4 C) o9 m9 M" Q3 M' b1 q1 M4 E# d
和正常情况一下,创建一个Win32 Application工程.
6 B. b1 P4 n3 F5 l* {8 _在调用Dll的时候,分两种调用,一种显示,一种是隐式.
) L8 b9 ~! X! V6 |这里分别讲述.
7 }) W9 k" N$ V9 N1 ?在进行下面代码之前,请将MyFirstDll.h,MyFirstDll.dll,MyFirstDll.Lib复制到刚创建的工程目录. 4 M4 v+ o1 d* O- ^# J
+ ~. Z& [& @2 J8 \9 [
* D  w( w) ^5 A& {
隐式调用.其使用方法和使用Lib文件无区别. 3 k) ~7 ?" i7 L+ P* Y

0 k" X8 Z" |5 {<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
7 |6 q& o4 O* r1 n* ^/ j$ F; n" l+ N: b
<TR>
0 z; W% Z5 u. @) m$ y( S<TD><B>代码:</B></TD></TR>1 G2 R' r4 v! i& ], c; P
<TR>
8 [9 x; W& h& B4 t* U! k0 N<TD class=code>2 r6 Z: ]8 E9 b
#include &lt;windows.h&gt; 4 x: E% a( ^+ \+ o) U. c7 m
#include "MyFirstDll.h"
. p0 F+ T6 l- g1 K9 x1 J0 [8 S
8 V* q/ S: S0 ]0 ]% w0 ZLRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
( _+ z2 E) y5 A6 @4 c& G8 i! {! I: m$ g" @* Y
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
' Z5 ^( D% E/ H                    PSTR szCmdLine, int iCmdShow)
6 T0 G8 |( i+ o& ]& c{   Y5 R% M+ I5 k; j! ?$ r) \+ c
     static TCHAR szAppName[] = TEXT ("TestDll") ; " A$ R1 e! M0 f4 J$ X% l
     HWND         hwnd ;
5 N% J. l) V" ^5 R, G     MSG          msg ;
- t: ~( f5 O% W, o4 X     WNDCLASS     wndclass ;
; g$ u. o4 b  J- Q$ G7 B3 P9 ~! x$ H9 E: m! T
     wndclass.style         = CS_HREDRAW | CS_VREDRAW ; # a0 ]( |; w9 h  I# S+ E! `
     wndclass.lpfnWndProc   = WndProc ;
( a8 m* w* k& g# I! M5 [1 d     wndclass.cbClsExtra    = 0 ;
2 R$ ?+ X. l' a, d     wndclass.cbWndExtra    = 0 ;
: I& h3 k) K2 `+ E' Z3 r+ m0 d     wndclass.hInstance     = hInstance ;
7 t4 i/ j9 x3 E6 S     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
" H" V) v/ y4 i1 G     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ; $ q+ y9 e; x; u( ?+ X' ^
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
  T" j) A: h9 ^1 f3 M% Q1 h( Z7 n     wndclass.lpszMenuName  = NULL ; ; s) w4 ?; E0 v/ _4 R6 A' o5 T- B5 F
     wndclass.lpszClassName = szAppName ; / v6 |+ Y2 ~7 T4 p. [
      ; i' u* x. h7 k" ]4 }
     if (!RegisterClass (&amp;wndclass))
) [* u) o0 t' k' q  b' w     { ; \/ L0 d% c& t0 I/ G
          MessageBox (NULL, TEXT ("This program requires Windows NT!"), & @7 G- Y$ _0 J& Q
                      szAppName, MB_ICONERROR) ;
8 D3 I" g8 Y+ ~  M+ V          return 0 ;
* J6 E- @* d. e. K( I+ {     }
, w  r  t) b/ j+ }      
/ R0 D1 g& x" `1 |8 m7 Z     hwnd = CreateWindow (szAppName, TEXT ("DLL Demonstration Program"),
4 f& F7 G7 V! O  ~: z" ?3 v                          WS_OVERLAPPEDWINDOW,
, S, v' m9 G; ~' I; z                          CW_USEDEFAULT, CW_USEDEFAULT,
+ q3 @$ E3 k% O1 z% P                          CW_USEDEFAULT, CW_USEDEFAULT, - M. h5 [0 U2 k: ?* z
                          NULL, NULL, hInstance, NULL) ;
4 q  f& m; W3 }8 Q+ V, l/ I( h5 n      
. q! U' a0 P+ \% S     ShowWindow (hwnd, iCmdShow) ;
  G7 t% e+ U  F6 p+ `3 p     UpdateWindow (hwnd) ;
# ^; c$ n+ G$ |* f+ T      
! u. V; V9 V- `* R  B6 ~     while (GetMessage (&amp;msg, NULL, 0, 0))
3 o1 I" m3 _5 K( ?' a' T1 X2 V     {   @/ s$ d; u" D- k% F
          TranslateMessage (&amp;msg) ; 8 I' W! T4 [. f; ^
          DispatchMessage (&amp;msg) ;
' b7 l8 x% m, [9 s     }
6 g( t' B  _' S. R& S     return msg.wParam ; 6 l3 g- R  W7 I) _" Z3 [( F- ]6 ^
} , R2 B$ j. H( a( i6 g( W7 m' g
. d1 f% Z" G% |& G, {
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) : F4 V6 b5 z- e  u9 r, m# n* I; `
{
8 u" N) h' X) {1 o+ E8 O     HDC         hdc ; # [2 Y  b7 ?5 O7 a
     PAINTSTRUCT ps ; % [3 `9 O' [, b% t" h
     RECT        rect ;
- D/ q( I, |% l# M' ^, @7 z      " P. Z$ |7 B2 J5 b) r! [) }/ k  }3 x5 s
     switch (message)   R) r) @) Z" r
     {
- @# I  T: K( a     case WM_PAINT: 9 m( Y$ q# P& a  @  s4 D
          hdc = BeginPaint (hwnd, &amp;ps) ; ; Q/ ?" W- P: J7 X! [7 [
         
7 S- C8 I6 r- ~          GetClientRect (hwnd, &amp;rect) ;
. b& }2 y0 D; y) v          + a' z# N6 A9 v! p
          EdrCenterText (hdc, &amp;rect,
" C1 V1 G& Z  D! a! N: L- R( r                         TEXT ("This string was displayed by a DLL")) ; 5 C, S* H6 T: w/ F* z. K
          ( x5 n+ ^8 L9 V/ [) R- C5 W  B# a
          EndPaint (hwnd, &amp;ps) ;
5 F) o5 m' m0 V          return 0 ; / r* N- O1 ?! R% y/ k
         
6 d" w( @) v4 [6 ~8 [     case WM_DESTROY:
& e" V7 @7 ?, N8 D" z          PostQuitMessage (0) ;
1 O8 y- D3 P7 n' A. E( u- a. k, X          return 0 ; / b+ N, J+ h) r9 U4 u' P! M2 q
     } * [4 e5 g2 ~  A+ w7 n4 ?) s2 ^
     return DefWindowProc (hwnd, message, wParam, lParam) ;
4 I" o1 M. \( \; x- ^( ^} - M! g0 H, U* y: O% v
</TD></TR></TABLE>% _8 t2 b* s6 ?+ P2 X
那么显示调用又是怎么回事.
( Q: \% |7 l6 H/ X大家看下面.
# c0 X% Q" x9 O. Y% U8 p# L$ r7 r% b1 X+ H$ @% X* ~
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>9 N$ U( s4 ]: d% v/ ^5 d

1 h8 z  Q6 _1 b% K' `<TR>
8 T+ m9 k# G/ [+ s4 S<TD><B>代码:</B></TD></TR>
( |0 k8 J3 Y- g8 G8 [2 q<TR>0 ^9 h! M8 \4 g; ?& C6 h( a
<TD class=code>. ?3 Q2 H4 X: `7 S4 q; w: D
typedef BOOL (WINAPI* MyEdrCenterText)(HDC,PRECT,PCWSTR);
  a: q# g' f  k( S$ \+ c2 MHANDLE hLibrary;   }+ v9 Z: C) d: {
MyEdrCenterText myEdrCenterText;
6 V# D) m; x& y7 U' v6 F) k3 _+ s6 f4 N6 J
hLibrary = LoadLibrary(TEXT("MyFirstDll.Dll");
: d! L% i, R6 r2 |6 ]# jmyEdrCenterText=(MyEdrCenterText)GetProcAddress(hLibrary,TEXT("EdrCenterText));
0 H& o3 Z1 {' amyEdrCenterText(hdc,&amp;rect,TEXT("你的话"));
* ^2 W$ P2 b9 w
1 ]1 [) Y; N$ M! z( r& X' U) EFreeLibrary(hLibrary);
+ I4 s% b. b  h* `8 Q</TD></TR></TABLE>( H0 U7 a4 K% H7 P6 V

. B! \: w" n+ t# J6 ^% K% i0 A这种调用不需要头文件.但是保存DLL在系统目录或在当前目录里.
& Z/ N4 C  c- f$ ^: L9 q
) g2 C' v" A9 S$ y, C* O0 J% _0 S4 ^

" B$ t, a) G7 E' A; u9 U; Y. r. K上面的示例都是Win32示例.不涉入VC的关键字.可以移植到BCB下, : Z% i9 t4 ?8 N7 f# F$ E
在BCB下建议用一种规范化格式来创建并使用DLL. 1 v; @/ D3 e! j( Z' @
. b6 p# U; Y4 h0 n2 ~9 k; _! P
我感觉VC在这方面走的比较前,也比较规范~
' a" m! T8 G. K! z  p6 ~2 r# T, h1 u7 E
以上示例采自&lt;&lt;Windows 程序设计&gt;&gt;第五版.




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