㈠ 用C語言編寫DLL
下面就是一個dll的主函數。加上一個空的導出函數.鏈接的時候目標是dll或者建立dll工程專。連接器裡面有設置
#include
__declspec(dllexport)
void
FuncInDll
(void)
{}
BOOL
APIENTRY
DllMain(HANDLE
hMole,
DWORD
dwReason,
void*
lpReserved)
{
HANDLE
g_hMole;
switch(dwReason)
{
case
DLL_PROCESS_ATTACH:
g_hMole
=
(HINSTANCE)hMole;
break;
case
DLL_PROCESS_DETACH:
g_hMole=NULL;
break;
}
return
TRUE;
}
注冊屬表操作有一系列API函數可以調用。你可以在MSDN搜索以Reg開頭的API如RegOpenKey,然後旁邊一堆相關的注冊表API。
注冊表鍵值HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run下添加項可以實現開機啟動。
當然還有其它方法。
㈡ 用C語言編寫DLL
下面就是一個dll的主函數。加上一個空的導出函數.鏈接的時候目標是dll或者建立dll工程。連接器裡面有設置
#include<windows.h>
__declspec(dllexport) void FuncInDll (void)
{}
BOOL APIENTRY DllMain(HANDLE hMole, DWORD dwReason, void* lpReserved)
{
HANDLE g_hMole;
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
g_hMole = (HINSTANCE)hMole;
break;
case DLL_PROCESS_DETACH:
g_hMole=NULL;
break;
}
return TRUE;
}
注冊表操作有一系列API函數可以調用。你可以在MSDN搜索以Reg開頭的API如RegOpenKey,然後旁邊一堆相關的注冊表API。
注冊表鍵值HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run下添加項可以實現開機啟動。
當然還有其它方法。
㈢ 怎麼在c語言中自己寫庫函數
1、不同的系統開發函數庫的具體步驟是不一樣的,這主要決定於編譯、鏈接環境。
2、不同的庫開發方式也不一樣,現在主流的庫開發有兩種,一種是靜態庫,一種是動態庫,兩者的本質區別是庫代碼是否和程序融合在一起,如果組裝在一起就是靜態庫,如果不組裝在一起,即為動態庫,現在操作系統提供的多數是動態庫,如Linux平台的.so文件,windows平台的DLL文件。
3、以Windows平台為例,用戶可以通過Vc/vs等IDE集成開發環境,生成DLL工程,然後編寫def文件進行導出。
㈣ 用c語言創建一個庫
你可以寫一個沒有主函數的程序,裡面全是子函數。
編譯時只產生 .obj 文件。
VC++ 編譯器 編譯命令里 選用 /c
.obj 文件 就是庫。
寫一個頭文件,包含這些子程序的函數原型聲明。
調用這個庫時,只要加入頭文件,鏈接時鏈接這個.obj 文件,就是用庫了。
unix 的 .a 庫, 就是.o 的集合體,.so 是另一種集合體。
動態鏈接庫和win32靜態庫要在建工程時選擇,用Visual Studio建程序框架。
㈤ C語言如何生成庫文件
這里以VC6.0開發工具來做說明,首先創建一個新的工程,工程類型選擇DLL(動態)類型,這時工具會自動為你創建一個.c和一個.h文件,可以根據自己的實際需要在.c和.h文件中加入代碼,編譯後就會生成和工程同名的動態庫文件和靜態庫文件。如果沒有做設置修改,以Debug方式編譯,生成的庫文件都存放在./Debug目錄下,如果在Release方式編譯,生成的庫文件都存放在./Relese目錄下。
㈥ 如何用C語言讀寫文件
c語言讀寫文件程序:
#include "stdio.h"
#include <stdlib.h>
main()
{
FILE *fp1;//定義文件流指針,用於打開讀取的文件
FILE *fp2;//定義文件流指針,用於打開寫操作的文件
char text[1024];//定義一個字元串數組,用於存儲讀取的字元
fp1 = fopen("d:\a.txt","r");//只讀方式打開文件a.txt
fp2 = fopen("d:\b.txt","w");//寫方式打開文件a.txt
while(fgets(text,1024,fp1)!=NULL)//逐行讀取fp1所指向文件中的內容到text中
{
puts(text);//輸出到屏幕
fputs(text,fp2);//將內容寫到fp2所指向文件中
}
fclose(fp1);//關閉文件a.txt,有打開就要有關閉
fclose(fp2);//關閉文件b.txt
}
C語言文件讀寫操作總結
一.非標准文件的讀寫 不帶緩沖的
1.文件的打開和關閉
open()函數的作用是打開文件,其調用格式為: int open(char *filename, int access); 該函數表示按access的要求打開名為filename的文件,返回值為文件描述字,其中access有兩部分內容: 基本模式和修飾符, 兩者用" "("或")方式連接,修飾符可以有多個, 但基本模式只能有一個。
access的規定
O_RDONLY 只讀
O_APPEND 文件指針指向末尾
O_WRONLY 只寫
O_CREAT 文件不存在時創建文件, 屬性按基本模式屬性
O_RDWR 讀寫
O_BINARY 打開一個二進制文件
O_TEXT 打開一個文字文件
open()函數打開成功, 返回值就是文件描述字的值(非負值), 否則返回-1。 close()函數的作用是關閉由open()函數打開的文件, 其調用格式為: int close(int handle); 該函數關閉文件描述字handle相連的文件。
2.讀寫函數
int read(int handle, void *buf, int count);
read()函數從handle(文件描述字)相連的文件中, 讀取count個位元組放到buf所指的緩沖區中, 返回值為實際所讀位元組數, 返回-1表示出錯。返回0 表示文件結束。
write()函數的調用格式為: int write(int handle, void *buf, int count); write()函數把count個位元組從buf指向的緩沖區寫入與handle相連的文件中, 返回值為實際寫入的位元組數。
3.隨機定位函數
lseek()函數的調用格式為: int lseek(int handle, long offset, int fromwhere);
該函數對與handle相連的文件位置指針進行定位,功能和用法與fseek()函數相同。 tell()函數的調用格式為: long tell(int handle); 該函數返回與handle相連的文件現生位置指針, 功能和用法與ftell()相同
二、標准文件的讀寫
1.文件的打開函數fopen()
文件的打開操作表示將給用戶指定的文件在內存分配一個FILE結構區,並將該結構的指針返回給用戶程序,以後用戶程序就可用此FILE指針來實現對指定文件的存取操作了。
當使用打開函數時,必須給出文件名、文件操作方式(讀、寫或讀寫),如果該文件名不存在,就意味著建立(只對寫文件而言,對讀文件則出錯),並將文件指針指向文件開頭。若已有一個同名文件存在,則刪除該文件,若無同名文件,則建立該文件,並將文件指針指向文件開頭。
fopen(char *filename,char *type);
其中*filename是要打開文件的文件名指針,一般用雙引號括起來的文件名表示,也可使用雙反斜杠隔開的路徑名。
而*type參數表示了對打開文件的操作方式。其可採用的操作方式如下:
"r" 打開,只讀; "w" 打開,文件指針指到頭,只寫; "a" 打開,指向文件尾,在已存在文件中追加; "rb" 打開一個二進制文件,只讀; "wb" 打開一個二進制文件,只寫; "ab" 打開一個二進制文件,進行追加 ;
"r+" 以讀/寫方式打開一個已存在的文件; "w+" 以讀/寫方式建立一個新的文本文件 ;"a+" 以讀/寫方式打開一個文件文件進行追加 ;"rb+" 以讀/寫方式打開一個二進制文件; "wb+" 以讀/寫方式建立一個新的二進制文件 ;
"ab+" 以讀/寫方式打開一個二進制文件進行追加 ;當用fopen()成功的打開一個文件時,該函數將返回一個FILE指針,如果文件打開失敗,將返回一個NULL指針。
㈦ c語言編程中怎麼用文件存儲數據具體一點,謝謝
主要用C語言的庫函數,有open write read 或者是fopen fwrite fread這幾個函數,迅速就是先open 然後write,具體函數的用法可自行網路,如果你是問存儲數據的格式的話,自己定義結構體存儲的方式是最方便直接的
㈧ C語言庫函數如何編寫
/***
*printf.c - print formatted
*
* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
* defines printf() - print formatted data
*
*******************************************************************************/
#include
#include
#include
#include
#include
#include
#include
/***
*int printf(format, ...) - print formatted data
*
*Purpose:
* Prints formatted data on stdout using the format string to
* format data and getting as many arguments as called for
* Uses temporary buffering to improve efficiency.
* _output does the real work here
*
*Entry:
* char *format - format string to control data format/number of arguments
* followed by list of arguments, number and type controlled by
* format string
*
*Exit:
* returns number of characters printed
*
*Exceptions:
*
*******************************************************************************/
int __cdecl printf (
const char *format,
...
)
/*
* stdout ''PRINT'', ''F''ormatted
*/
{
va_list arglist;
int buffing;
int retval;
va_start(arglist, format);
_ASSERTE(format != NULL);//斷言宏。如果輸出格式字元串指針為空,則在DEBUG版下斷言,報告錯誤。
_lock_str2(1, stdout);
buffing = _stbuf(stdout);//stdout:指定輸出到屏幕
retval = _output(stdout,format,arglist);
_ftbuf(buffing, stdout);
_unlock_str2(1, stdout);
return(retval);
}
以上為printf()的源代碼
1、從含有可選參數函數中獲得可選參數,以及操作這些參數
typedef char *va_list;
void va_start( va_list arg_ptr, prev_param );
type va_arg( va_list arg_ptr, type );
void va_end( va_list arg_ptr );
假定函數含有一個必選參數和多個可選參數,必選參數聲明為普通數據類型,且能通過參數名來獲得該變數的值。可選參數通過宏va_start、va_arg和va_end(定義在stdarg.h或varargs.h中)來進行操作,即通過設置指向第一個可選參數指針、返回當前參數、在返回參數後重新設置指針來操作所有的可選參數。
va_start:為獲取可變數目參數的函數的參數提供一種便捷手段。設置arg_ptr為指向傳給函數參數列表中的第一個可選參數的指針,且該參數必須是va_list類型。prev_param是在參數列表中第一個可選參數前的必選參數。
va_arg:返回由arg_ptr所指向的參數的值,且自增指向下一個參數的地址。type為當前參數的類型,用來計算該參數的長度,確定下一個參數的起始位置。它可以在函數中應用多次,直到得到函數的所有參數為止,但必須在宏va_start後面調用。
va_end:在獲取所有的參數後,設置指針arg_ptr為NULL。
下面舉例說明:
#include
#include
int average( int first, ... );
void main( void )
{
/* Call with 3 integers (-1 is used as terminator). */
printf( "Average is: %d\n", average( 2, 3, 4, -1 ) );
/* Call with 4 integers. */
printf( "Average is: %d\n", average( 5, 7, 9, 11, -1 ) );
/* Call with just -1 terminator. */
printf( "Average is: %d\n", average( -1 ) );
}
int average( int first, ... )
{
int count = 0, sum = 0, i = first;
va_list marker;
va_start( marker, first ); /* Initialize variable arguments. */
while( i != -1 )
{
sum += i;
count++;
i = va_arg( marker, int);
}
va_end( marker ); /* Reset variable arguments. */
return( sum ? (sum / count) : 0 );
}
返回值為:
Average is: 3
Average is: 8
Average is: 0
綜上所述,在printf()函數中,可以只輸出一個字元串,也可按照一定的形式輸出含有多個可選參數的字元串信息。因此,首先就要通過這些宏來獲取所有的可選參數。在上面的源碼可以看出printf()中,只使用了宏at_start,將可選參數的首地址賦給了arglist。
2、鎖定字元串及輸出字元串到屏幕
#define _lock_str2(i,s) _lock_file2(i,s)
void __cdecl _lock_file2(int, void *);
#define _unlock_str2(i,s) _unlock_file2(i,s)
void __cdecl _unlock_file2(int, void *);
int __cdecl _stbuf(FILE *);
void __cdecl _ftbuf(int, FILE *);
int __cdecl _output(FILE *, const char *, va_list);
在output函數中,讀取格式字元串中的每一個字元,然後對其進行處理,處理方式根據每一個字元所代表的意義來進行,如:普通字元直接利用函數WRITE_CHAR(ch, &charsout);輸出到控制台。
其中的主要部分是對轉換說明符(d,c,s,f)的處理,現在將對其中的部分代碼進行詳細說明,這里只說明最基本的轉換說明符,對這些須基本的轉換說明符進行修飾的修飾符,程序中單獨進行處理。下面是函數output()(output.c)部分源代碼:
case ST_TYPE:
//表示當前處理的字元的類型為轉換說明符。
...
switch (ch) {
//下面對參數的獲取都是利用宏va_arg( va_list arg_ptr, type );來進行的。
case ''c'': {
//從參數表中獲取單個字元,輸出到緩沖字元串中,此時,type=int
buffer[0] = (char) get_int_arg(&argptr); /* get char to print */
text = buffer;
textlen = 1; /* print just a single character */
}
break;
case ''s'': {
//從參數表中獲取字元串,輸出到緩沖字元串中,此時,type=char*
int i;
char *p; /* temps */
text = get_ptr_arg(&argptr);
...
}
break;
case ''w'': {
//對寬字元進行處理
...
} /* case ''w'' */
break;
...
case ''e'':
case ''f'':
case ''g'': {
//對浮點數進行操作
...
#if !LONGDOUBLE_IS_DOUBLE
/* do the conversion */
if (flags & FL_LONGDOUBLE) {
_cldcvt((LONGDOUBLE*)argptr, text, ch, precision, capexp);
va_arg(argptr, LONGDOUBLE);
//對長雙精度型進行處理,此時,type=long double
}
else
#endif /* !LONGDOUBLE_IS_DOUBLE */
{
//對雙精度型進行處理,此時,type=double
_cfltcvt((DOUBLE*)argptr, text, ch, precision, capexp);
va_arg(argptr, DOUBLE);
}
...
break;
//對整型變數處理
case ''d'':
case ''i'':
...
goto COMMON_INT;
case ''u'':
radix = 10;
goto COMMON_INT;
case ''p'':
...
goto COMMON_INT;
case ''o'':
...
註:對於浮點型double和long double,有相應的轉換說明符(%f表示雙精度型,%lf表示長雙精度型),而float卻沒有。其中的原因是,在K&RC下,float值用於表達式或用作參數前,會自動轉換成double類型。而ANSI C一般不會自動把float轉換成double。有些程序已假定其中的float參數會被轉換成double,為了保護大量這樣的程序,所有printf()函數的float參數還是被自動轉換成double型。因此,在K&RC或ANSI C下,都無需用特定的轉換說明符來顯示float型。
綜上所述,轉換說明符必須與待列印字元的類型。通常,用戶有種選擇。例如,如要列印一個int類型的值。則只可以使用%d,%x或%o。所有這些說明符都表示要列印一個int類型的值;它們只不過提供了一個數值的幾種不同表示。類似一,可以用%f、%g和%e來表示double類型的值。但如果轉換說明與類型不匹配,將會出現意想不到的結果。為什麼呢?問題就在於C向函數傳遞信息的方式。
這個失敗的根本細節與具體實現相關。它決定了系統中的參數以何方式傳遞。函數調用如下:
float n1;
double n2;
long n3;
long n4;
...
printf("%ld,%ld,%ld,%ld",n1,n2,n3,n4);
這個調用告訴計算機,要把變數n1,n2,n3和n4的值交給計算機,它把這些變數放進稱作棧(stack)的內存區域中,來完成這一任務。計算機把這些值放進棧中,其根據是變數的類型而不是轉換說明符,比如n1,把8個位元組放入棧中(float被轉換成double),類似地,為n2放了8位元組,其後給n3和n4各放了4個位元組。接著,控制的對象轉移到printf();此函數從棧中讀數,不過在這一過程中,它是在轉換說明符的指導下,讀取數值的。說明符%ld指定printf()應讀4個位元組(va_arg( va_list arg_ptr, type )中type=long),因此printf()讀入棧中的4個位元組,作為它的第一個值。但是這只是n1的前半部分,這個值被看成一個long整數。下一個說明符%ld讀入4個位元組,這正是n1的後半部分,這個值被看成第二個long整數。類似地,第三、第四次又讀入n2的前後兩部分。因此,盡管我們對n3和n4使用了正確的說明符,printf()仍然會產生錯誤。
㈨ C語言基礎 之 文件基礎
所謂文件一般是指存儲在外部介質上的 數據集合 。一批數據是以 文件 的形式存放在外部介質的。操作系統是以文件為單位對數據進行管理的。
按數據的組織方式,數據文件可以分為有 結構文件 和 無結構文件 兩類。
C語言使用的是 流式文件 。常見的 文本文件 和 二進制文件 屬於流式文件。
ANSI C 標准 對文件的處理方法是 「緩沖文件系統」 ,系統為每個打開文件在內存中開辟一個緩沖區。寫文件時(從內存向磁碟輸出數據),先送到緩沖區中,當緩沖區裝滿後才送到磁碟中去。讀文件時,也經過緩沖區。這樣做是為了提高讀寫效率,因為磁碟訪問更耗時,一次讀寫一塊數據, 比每次讀寫單個字元更經濟。
緩沖文件系統中,關鍵的概念是 「文件指針」 。每個被用的文件都在內存中開辟一個區,用來存放文件的名字、狀態、位置等有關信息,這些信息是保存在個結構體類型的變數中的。該結構體類型是由系統定義的,取名為FILE。有的C語言版本在stdio.h 文件中有以下類型定義。
有了FILE類型之後,可以用它定義若干個FILE結構體類型的變數,以便存放若干個文件信息。
稱指向FILE結構體類型的變數為文件類型指針,稱為文件指針。定義文件指針的一般形式:
FILE * 指針變數名;
通常把打開文件的FILE結構的首地址賦給文件指針。
在文件操作時,首先要打開文件,獲得對該文件的指針。通過該指針,就可以獲取對文件進行操作所需的信息。將該指針傳遞給相應的庫函數,庫函數就能通過這個信息,通過操作系統提供的文件系統調用,來完成低級且復雜的硬體操作,如磁碟的讀與。
在C語言中,調用庫函數fopen打開文件。該函數的調用方式通常為:
說明:
①函數的兩個參數「文件名」和「使用文件方式」均為字元串,其中表示文件名的字元串可以包含文件的存儲路徑,否則表示文件存儲在當前目錄下。
②使用文件的方式及其含義如表8-1所示。
例如:
其意義是在當前目錄下打開文件file1.txt,只允許進行「讀」操作,並使fp指向file.txt。
其意義是在example目錄下打開文件file2.txt,只允許進行「寫」操作,並使fp指向file2.txt。
文件使用完畢,必須將其關閉以免發生文件數據丟失等錯誤。
關閉文件可調用庫函數fclose來實現。
該函數的使用格式通常為:
fclose(文件指針);
說明:
將文件指針與文件脫離聯系。如果成功進行關閉操作時,函數返回0,否則返回非0。
例如:
flose(fp); //關閉文件指針fp指向的文件
㈩ 如何用VC編寫dll文件
http://dev.csdn.net/Develop/article/19/19966.shtm
在我們實際用軟體時,經常可看到許多動態連接庫。動態連接庫有其自身的優點
如節省內存、支持多語種等功能,而且,當DLL中的函數改變後,只要不是參數的改變
調用起的函數並不需要重新編譯。這在編程時十分有用。至於其他妙處,各位在電腦
雜志、書籍中都能看到,我這里再說就是廢話了.
這次小弟我所要講的是如何在VC5.0中如何做自己的Win32 DLLs,各位要做自己的
動態連接庫,首先要知道DLL在VC5.0中都有哪幾種分類。VC支持三種DLL,它們是:
1.Non-MFC Dlls
2.Regular Dlls
3.Extension Dlls Note:翻譯措辭不當,故遇到術語是引用原詞
Non-MFC DLL:指的是不用MFC的類庫結構,直接用C語言寫的DLL,其輸出的函數一
般用的是標准C介面,並能被非MFC或MFC編寫的應用程序所調用。LL,
Regular DLL:和下述的Extension Dlls一樣,是用MFC類庫編寫的。明顯的特點是
在源文件里有一個繼承CWinApp的類。其又可細分成靜態連接到MFC和動態連接到MFC上
的。但靜態連接到MFC的動態連接庫只被VC的專業般和企業版所支持。
Extension DLL:用來實現從MFC所繼承下來的類的重新利用,也就是說,用這種類
型的動態連接庫,可以用來輸出一個從MFC所繼承下來的類。Extension DLL使用MFC的
動態連接版本所創建的,並且它只被用MFC類庫所編寫的應用程序所調用。
各位看到這里如果眼有點花或頭有點暈,請別泄氣,再看兩遍,然後繼續往下看,
定有收獲。
標 題: 關於VC中的DLL的編程[1]
這一節介紹Non-MFC DLLs的編寫方法。下面是一個通用的
寫法:
BOOL APIENTRY DllMain(HANDLE hMole,DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch( ul_reason_for_call ) {
case DLL_PROCESS_ATTACH:
.......
case DLL_THREAD_ATTACH:
.......
case DLL_THREAD_DETACH:
.......
case DLL_PROCESS_DETACH:
.......
}
return TRUE;
}
每一個DLL必須有一個入口點,這就象我們用C編寫的應用程序一樣,
必須有一個WINMAIN函數一樣。
在這個示例中,DllMain是一個預設的入口函數,你不需要編寫自己
的DLL入口函數,並用linker的命令行的參數開關/ENTRY聲明。用這個缺
省的入口函數就能使動態連接庫被調用時得到正確的初始化,當然了,你
不要在初始化的時候填寫使系統崩潰的代碼了。
參數中,hMoudle是動態庫被調用時所傳遞來的一個指向自己的句柄
(實際上,它是指向_DGROUP段的一個選擇符)
ul_reason_for_call是一個說明動態庫被調原因的標志。當進程或線程
裝入或卸載動態連接庫的時候,操作系統調用入口函數,並說明動態連接庫
被調用的原因。它所有的可能值為:
DLL_PROCESS_ATTACH: 進程被調用
DLL_THREAD_ATTACH: 線程被調用
DLL_PROCESS_DETACH: 進程被停止
DLL_THREAD_DETACH: 線程被停止
lpReserved是一個被系統所保留的參數。
入口函數已經寫了,盛下的也不難,你可以在文件中加入你所想要輸
出的函數或變數或c++類或、或、或、?好象差部多了。Look here!現在就
要加入一個新的輸出函數了:
void _declspec(dllexport) JustSoSo()
{
MessageBox(NULL,"It's so easy!","Hahaha......",MB_OK);
}
要輸出一個類也可以,如下:
class _declspec(dllexport) Easy
{
//add your class definition...
};
各位一定注意到在輸出函數或類是我用到_declspec(dllexport),
這是VC提供的一個關鍵字,用它可在動態連接庫中輸出一個數據、
一個函數或一個類。用這個關鍵字可省你不少事,你不用在.DEF文件
中說明我要輸出這個類、那個函數的。
Ok!各位照著上面的例子試著敲敲看,Just so easy!
先說到這了
發信人: dragon (龍), 信區: VC
標 題: 關於VC中的DLL的編程[2]
前面講到Non-MFC DLL的編法,現在講講調用DLL的方法。對DLL的
調用分為兩種,一種是顯式的調用,一種是隱式的調用。
所謂顯式的調用,是指在應用程序中用LoadLibrary或MFC提供的
AfxLoadLibrary顯式的將自己所做的動態連接庫調近來,動態連接庫
的文件名即是上兩函數的參數,再用GetProcAddress()獲取想要引入
的函數。自此,你就可以象使用如同本應用程序自定義的函數一樣來
調用此引入函數了。在應用程序退出之前,應該用FreeLibrary或
MFC提供的AfxLoadLibrary釋放動態連接庫。
隱式的調用則需要把產生動態連接庫時產生的.LIB文件加入到應
用程序的工程中,想使用DLL中的函數時,只須說明以下,如下:說明
上篇的輸出函數void JustSoSo();
隱式調用不需要調用LoadLibrary()和FreeLibrary().
由此看來,隱式說明調用的方法比較簡單,但DLL改變後,應用程序
須從新編譯。並且,所有所調用的DLL在應用程序載入的同時被載入到內
存中,但應用程序調用的DLL比較多時,裝入的過程十分慢。隱式的調用
則在應用程序不知道所要裝入的DLL或隱式調用不成功,此時,允許用戶
指定所要載入的動態連接庫,比較靈活
發信人: dragon (龍), 信區: VC
標 題: 關於VC中的DLL的編程[3]
Regular DLL能夠被所有支持DLL技術的語言所編寫的應用程序
所調用。在這種動態連接庫中,它必須有一個從CWinApp繼承下來的
類,DllMain函數被MFC所提供,不用自己顯式的寫出來。下面是一個
例子:
// MyRegularDll.h:main header file for the MYREGULARDLL DLL
#include "resource.h" // main symbols
class CMyRegularDllApp : public CWinApp
{
public:
CMyRegularDllApp();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMyRegularDllApp)
//}}AFX_VIRTUAL
//{{AFX_MSG(CMyRegularDllApp)
// NOTE - the ClassWizard will add and
// remove member functions here.
// DO NOT EDIT what you see in these blocks
// of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//MyRegularDll.cpp:Defines the initialization routines for the DLL.
//
#include "stdafx.h"
#include "MyRegularDll.h"
// Note!
//
// If this DLL is dynamically linked against the MFC
// DLLs, any functions exported from this DLL which
// call into MFC must have the AFX_MANAGE_STATE macro
// added at the very beginning of the function.
//
// For example:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticMoleState());
// // normal function body here
// }
//
// It is very important that this macro appear in each
// function, prior to any calls into MFC. This means that
// it must appear as the first statement within the
// function, even before any object variable declarations
// as their constructors may generate calls into the MFC
// DLL.
BEGIN_MESSAGE_MAP(CMyRegularDllApp, CWinApp)
//{{AFX_MSG_MAP(CMyRegularDllApp)
// NOTE - the ClassWizard will add
// and remove mapping macros here.
// DO NOT EDIT what you see in these blocks
END_MESSAGE_MAP()
////////////////////////////////////////////////////////////
// CMyRegularDllApp construction
CMyRegularDllApp::CMyRegularDllApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
以上是AppWizard產生的含有主要代碼的兩個文件,各位可從中
看出和Non-MFC Dlls的區別。但要注意上面的AppWizard的提醒啊。
發信人: dragon (龍), 信區: VC
標 題: 關於VC中的DLL的編程[4]
發信站: 飲水思源站 (Thu Mar 25 00:46:22 1999) , 站內信件
這次要講的是最後一種動態連接庫:Extension Dlls.再次說明,
Extension Dll只被用MFC類庫所編寫的應用程序所調用.在這種動態
連接庫中,你可以從MFC繼承你所想要的、更適於你自己用的類,並
把它提供給你的應用程序。你也可隨意的給你的應用程序提供MFC或
MFC繼承類的對象指針。
Extension DLLs 和Regular DLLs不一樣,它沒有一個從CWinApp
繼承而來的類的對象,所以,你必須為自己DllMain函數添加初始化
代碼和結束代碼.如下:
#include "stdafx.h"
#include
static AFX_EXTENSION_MODULE PROJNAMEDLL = { NULL, NULL };
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
TRACE0("PROJNAME.DLL Initializing!\n");
// Extension DLL one-time initialization
AfxInitExtensionMole(PROJNAMEDLL,
hInstance);
// Insert this DLL into the resource chain
new CDynLinkLibrary(Dll3DLL);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("PROJNAME.DLL Terminating!\n");
}
return 1; // ok
}
在上面代碼中AfxInitExtensionMoudle函數捕捉此動態庫模塊
用.
在初始化的時NEW一個CDynLinkLibrary對象的目的在於:它
能是Extension DLL想應用程序輸出CRuntimeClass對象或資源.
如果此動態連接庫被顯式的調用,還必須在DLL_PROCESS_DETACH
選擇項的執行代碼上調用AfxTermEXtensonMole,這保證了當調
用進程與動態連接庫分離是正確清理內存中的動態庫模塊。如果是
隱式的被調用,則此步不是必須的了。