ilikenba 发表于 2004-6-11 22:20

[转帖]关于DLL创建和使用的问题

先前在论坛上看了一下用BCB来写DLL的问题,我觉得讲的还不是很浅显
而且不够规范.有些地方,让人不明白.
所以我自己私下翻了一些资料,把自己这几天的体会告诉大家.虽然示例代码不是BCB的,但是
也可以说明一个思路.大家一定能够看得懂的.
这里都是以VC6.0,来创建DLL文件的.代码示例都来自<<Windows程序设计>>第五版.是Win SDK写的
没有使用任何VC方面的关键字~~没有使用MFC技术~而且很规范的方法~
建议大家应该学习这种一丝不苟的规范精神~~

一.动态连接库的创建

选择File->New,再选择Projects选择Win32 Dynamic-Link Library,然后在Project Name里输入
MyFirstDll.
这样子就建立了一个DLL工程.接下来.
选择File->New,Files选择C/C++ Header File. File项填入MyFirstDll.H
这样就创建好了头文件.
选择File->New,Files选择 C++ Source File .File项填入MyFirstDll.C

开始写头文件.代码如下:
MyFirstDll.H

<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>

<TR>
<TD><B>代码:</B></TD></TR>
<TR>
<TD class=code>
ifdef __cplusplus
#define EXPORT extern "C" __declspec (dllexport)
#else
#define EXPORT __declspec (dllexport)
#endif

EXPORT BOOL CALLBACK EdrCenterTextA (HDC, PRECT, PCSTR) ;
EXPORT BOOL CALLBACK EdrCenterTextW (HDC, PRECT, PCWSTR) ;

#ifdef UNICODE
#define EdrCenterText EdrCenterTextW
#else
#define EdrCenterText EdrCenterTextA
#endif
</TD></TR></TABLE>
MyFirstDll.C

<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>

<TR>
<TD><B>代码:</B></TD></TR>
<TR>
<TD class=code>
include &lt;windows.h&gt;
#include "edrlib.h"

int WINAPI DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
{
     return TRUE ;
}

EXPORT BOOL CALLBACK EdrCenterTextA (HDC hdc, PRECT prc, PCSTR pString)
{
     int  iLength ;
     SIZE size ;

     iLength = lstrlenA (pString) ;

     GetTextExtentPoint32A (hdc, pString, iLength, &amp;size) ;

     return TextOutA (hdc, (prc-&gt;right - prc-&gt;left - size.cx) / 2,
                           (prc-&gt;bottom - prc-&gt;top - size.cy) / 2,
                      pString, iLength) ;
}

EXPORT BOOL CALLBACK EdrCenterTextW (HDC hdc, PRECT prc, PCWSTR pString)
{
     int  iLength ;
     SIZE size ;

     iLength = lstrlenW (pString) ;

     GetTextExtentPoint32W (hdc, pString, iLength, &amp;size) ;

     return TextOutW (hdc, (prc-&gt;right - prc-&gt;left - size.cx) / 2,
                           (prc-&gt;bottom - prc-&gt;top - size.cy) / 2,
                      pString, iLength) ;
}
</TD></TR></TABLE>


上面这两个文件创建完成.
这两个文件中特殊之处,就是定义EXPORT标识标.其实在DLL中,应用程序使用的
函数必须是导出的.这样就确保函数名添加到MyFirstDll.Lib.
EXPORT包括保存类说明__declspec(dllexport),当头文件按C++模块编译时附加的"C"
以防止编译程序破坏C++的函数名.而且能够允许C和C++程序都能使用这个DLL


当库首次启动和结束时,我们就需要调用DllMain函数.
DllMain的第一个参数是库的实例.
DllMain的第二个参数fdwReason可以四个值之一,这四个值如下:
DLL_PROCESS_ATTACH :表示动态连接库被映射到一个进程的地址空间
DLL_PROCESS_DETACH :意味着进程不再需要DLL,从而提供给库自己请除自己的机会
DLL_THREAD_ATTACH :某个进程创建了一个新的进程
DLL_THREAD_DETACH :当使用这个调用DllMain时,线程仍然存在,这时线程可能在使用PostMessage前已经退出了.

编译上面的C++ Source File,得到一个MyFirstDll.dll.


二.动态链接库的调用方法

下面来调用和测试这个DLL

和正常情况一下,创建一个Win32 Application工程.
在调用Dll的时候,分两种调用,一种显示,一种是隐式.
这里分别讲述.
在进行下面代码之前,请将MyFirstDll.h,MyFirstDll.dll,MyFirstDll.Lib复制到刚创建的工程目录.


隐式调用.其使用方法和使用Lib文件无区别.

<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>

<TR>
<TD><B>代码:</B></TD></TR>
<TR>
<TD class=code>
#include &lt;windows.h&gt;
#include "MyFirstDll.h"

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("TestDll") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;

     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;
      
     if (!RegisterClass (&amp;wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
      
     hwnd = CreateWindow (szAppName, TEXT ("DLL Demonstration Program"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
      
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;
      
     while (GetMessage (&amp;msg, NULL, 0, 0))
     {
          TranslateMessage (&amp;msg) ;
          DispatchMessage (&amp;msg) ;
     }
     return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     HDC         hdc ;
     PAINTSTRUCT ps ;
     RECT        rect ;
      
     switch (message)
     {
     case WM_PAINT:
          hdc = BeginPaint (hwnd, &amp;ps) ;
         
          GetClientRect (hwnd, &amp;rect) ;
         
          EdrCenterText (hdc, &amp;rect,
                         TEXT ("This string was displayed by a DLL")) ;
         
          EndPaint (hwnd, &amp;ps) ;
          return 0 ;
         
     case WM_DESTROY:
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}
</TD></TR></TABLE>
那么显示调用又是怎么回事.
大家看下面.

<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>

<TR>
<TD><B>代码:</B></TD></TR>
<TR>
<TD class=code>
typedef BOOL (WINAPI* MyEdrCenterText)(HDC,PRECT,PCWSTR);
HANDLE hLibrary;
MyEdrCenterText myEdrCenterText;

hLibrary = LoadLibrary(TEXT("MyFirstDll.Dll");
myEdrCenterText=(MyEdrCenterText)GetProcAddress(hLibrary,TEXT("EdrCenterText));
myEdrCenterText(hdc,&amp;rect,TEXT("你的话"));

FreeLibrary(hLibrary);
</TD></TR></TABLE>

这种调用不需要头文件.但是保存DLL在系统目录或在当前目录里.



上面的示例都是Win32示例.不涉入VC的关键字.可以移植到BCB下,
在BCB下建议用一种规范化格式来创建并使用DLL.

我感觉VC在这方面走的比较前,也比较规范~

以上示例采自&lt;&lt;Windows 程序设计&gt;&gt;第五版.
页: [1]
查看完整版本: [转帖]关于DLL创建和使用的问题