㈠ 用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,这保证了当调
用进程与动态连接库分离是正确清理内存中的动态库模块。如果是
隐式的被调用,则此步不是必须的了。