DEV Windows下DLL程式設計技術及應用

2021-03-31 15:13:48 字數 4073 閱讀 4495

windows下dll程式設計技術及應用

一 、引 言

由於windows為微機提供了前所未有的標準使用者介面、圖形處理能力和簡單靈便的操作,絕大多數程式編制人員都已轉向或正在轉向windows程式設計。在許多使用者設計的實際應用系統的程式設計任務中,常常要實現軟體對硬體資源和記憶體資源的訪問,例如埠i/o、dma、中斷、直接記憶體訪問等等。若是編制dos程式,這是輕而易舉的事情,但要是編制windows程式,尤其是windowsnt環境下的程式,就會顯得較困難。

因為windows具有"與裝置無關"的特性,不提倡與機器底層的東西打交道,如果直接用windows的api函式或i/o讀寫指令進行訪問和操作,程式執行時往往就會產生保護模式錯誤甚至宕機,更嚴重的情況會導致系統崩潰。那麼在windows下怎樣方便地解決上述問題呢?用dll(dynamic link libraries)技術就是良好途徑之一。

dll是windows最重要的組成要素,windows中的許多新功能、新特性都是通過dll來實現的,因此掌握它、應用它是非常重要的。其實windows本身就是由許多的dll組成的,它最基本的三大組成模組kernel、gdi和user都是dll,它所有的庫模組也都設計成dll。凡是以.dll、.drv、.fon、.sys和許多以.exe為副檔名的系統檔案都是dll,要是開啟windows/system目錄,就可以看到許多的dll模組。儘管dll在ring3優先順序下執行,仍是實現硬體介面的簡便途徑。dll可以有自己的資料段,但沒有自己的堆疊,使用與呼叫它的應用程式相同的堆疊模式,減少了程式設計設計上的不便;同時,乙個dll在記憶體中只有乙個例項,使之能高效經濟地使用記憶體;dll實現的**封裝性,使得程式簡潔明晰;此外還有乙個最大的特點,即dll的編制與具體的程式語言及編譯器無關,只要遵守dll的開發規範和程式設計策略,並安排正確的呼叫介面,不管用何種程式語言編制的dll都具有通用性。例如在bc31中編制的dll程式,可用於bc、vc、vb、delphi等多種語言環境中。筆者在bc31環境下編譯了windows下直接記憶體訪問和埠i/o兩個dll,用在多個自製系統的應用軟體中,執行良好。

二、dll的建立和呼叫

dll的建立及呼叫方法在許多資料上有詳細的介紹,為了節省篇幅,在這裡僅作一些主要的概括。

1.dll的建立

關於dll的建立,有如下幾個方面的要素是不可缺少和必須掌握的:

入口函式libmain( )

就象c程式中的winmain( )一樣,windows每次載入dll時都要執行libmain( )函式,主要用來進行一些初始化工作。通常的形式是:

int far pascal libmain(hinstance hinstance,word wdataseg,word wheapsize,lpstr lpszcmdline)

出口函式wep( )

windows從記憶體中解除安裝dll時,呼叫相應的出口函式wep( ),主要做一些清理工作,如釋放占用的記憶體資源;丟棄某些字串、點陣圖等資源;關閉開啟的檔案等等。

自定義的輸出函式

為了讓位於不同記憶體段的應用程式進行遠端呼叫,自定義的輸出函式必須定義為遠端函式(使用far關鍵字),以防使用近程指標而得到意外的結果;同時,加上pascal關鍵字可加快程式的執行速度,使**簡單高效,提高程式的執行速度。

輸出函式的引出方法

在dll的模組定義檔案中(.def)由exports語句對輸出函式逐一列出。例如:

exports wep @1 residentname

//residentname可提高dll效率和處理速度

portin @2

portout @3 //通常對所有輸出函式附加系列號

在每個輸出函式定義的說明中使用_export關鍵字來對其引出。

以上兩種方法任選其中的一種即可,不可重複。後面的兩個例項分別使用了上述兩種不同的引出方式,請留意。

2.dll的呼叫

載入dll時,windows尋找相應dll的次序如下:

.當前工作盤。

windows目錄;getwindowsdirectory( )函式可提供該目錄的路徑名。

windows系統目錄,即system子目錄;呼叫getsystemdiretory( )函式可獲得這個目錄的路徑名。

dos的path命令中羅列的所有目錄。

網路中映象的目錄列表中的全部目錄。

dll模組中輸出函式的呼叫方法:

不論使用何種語言對編譯好的dll進行呼叫時,基本上都有兩種呼叫方式,即靜態呼叫方式和動態呼叫方式。靜態呼叫方式由編譯系統完成對dll的載入和應用程式結束時dll解除安裝的編碼(如還有其它程式使用該dll,則windows對dll的應用記錄減1,直到所有相關程式都結束對該dll的使用時才釋放它),簡單實用,但不夠靈活,只能滿足一般要求。動態呼叫方式是由程式設計者用api函式載入和解除安裝dll來達到呼叫dll的目的,使用上較複雜,但能更加有效地使用記憶體,是編制大型應用程式時的重要方式。具體來說,可用如下的方法呼叫.在應用程式模組定義檔案中,用imports語句列出所要呼叫dll的函式名。如:

imports

memorydll.memoryread

memorydll.memorywrite

讓應用程式執行時與dll模組動態鏈結

先用loadlibrary載入dll,再用getprocaddress函式檢取其輸出函式的位址,獲得其指標來呼叫。如:

handle hlibrary;

farproc lpfunc;

int portvalue;

hlibrary=loadlibrary("portdll.dll");

//載入dll

if(hlibrary>31) //載入成功

三、dll應用例項源程式

1.直接記憶體訪問的dll源**

//.def檔案

library

memorydll

description 'dll for memory_read_write '

exetype windows

code

preload moveable discardable

data preload moveable single

heapsize 1024

//dll無自己的堆疊,故沒有stacksize語句

exports wep @1 residentname

readmemory

@2writememory @3

//.cpp檔案

#include

int far pascal libmain(hinstance hinstance,word wdataseg,word wheapsize,lpstr lpszcmdline)

int far pascal memoryread(unsigned int dosseg,unsigned int dosoffset)

void far pascal memorywrite(unsigned int dosseg,unsigned int dosoffset,char data)

int far pascal wep(int nparam)

2.埠讀寫i/o的dll源**

//.def檔案

library portdll

description 'dll for

port_in_out '

exetype windows

code preload moveable discardable

data

preload moveable single

heapsize 1024

//.cpp檔案

#include

#include

int far pascal

libmain(hinstance hinstance,word wdataseg,word wheapsize,lpstr lpszcmdline)

int far pascal _export portout(int port,unsigned char value)

int far pascal _export portin(int port)

int far pascal _export wep(int nparam)

分別將上面兩個例項的.def檔案和.cpp檔案各自組成乙個.prj檔案,並進行編譯鏈結成.exe或.dll檔案就可以在應用程式中對其進行呼叫。

windows下搭建python cgi程式設計環境

順便把實習做的專案從unix系統轉到windows下面來了。安裝python,搭建機器學習開發環境前面的部落格提過了,不寫了。2 配置apache引數 修改配置檔案 conf httpd.conf,搜尋 options indexes followsymlinks,改為options indexes...

APACHE TOMCAT環境下JSP的編碼問題

今天又遇到亂碼問題,可真煩.為什麼tomcat就不能自動判斷專案的編碼,而一定要專案遵循tomcat的編碼.說說解決方法吧 在tomcat的server.xml配置檔案中的connector中新增uriencoding utf 8 屬性,如 如果是apache整合tomcat,則要在連線的conne...

vmware下初編linux問題

今天在vmware下編譯linux2.4.18核心,出現了乙個問題 mkinitrd initrd 2.4.26.img 2.4.26的時候出現錯誤 no module buslogic found for kernel 2.4.26 原來是vmware預設用的是scsi做硬碟驅動,核心裡面沒有選,...