win32学习记录day-11

  • 静态库程序 - 运行时不存在,会被链接
    到可执行文件或者动态库中,目标程序的归档。
    文件扩展名:LIB
  • 动态库程序 - 运行时独立存在,不会被链接到可执行文件或其他动态库中。
    文件扩展名:DLL

静态库程序

  1. 静态库特点
  • 运行时不存在
  • 链接到可执行文件或者动态库中
  • 目标程序的归档
  1. C语言静态库

    • 静态库的创建
      • 建项目
      • 添加库程序,源文件使用C文件
    • 库的路径设置
      • 项目的“Settings”中设置库的路径
      • 可以使用 pragma 关键字设置
    • c语言静态库的使用
      建立一个C文件,可以在文件中直接使用C库函数,不需要头文件。C编译器只是根据库函数名称,在库中找到对应的函数代码,进行链接。
  2. C++语言的静态库

    • 静态库的建立
      • 建立项目
      • 添加库程序,源文件使用CPP文件
    • 库的导入
      • 项目的“Setting”中设置库的路径
      • 可以使用 pragma 关键字设置
    • 注意
      在CPP环境使用C静态库,库中函数原型定义要增加 extern “C”, 例如:extern "C" int Add(... );

动态库程序

  1. 动态库特点

    • 运行时独立存在
    • 不会链接到执行程序
    • 使用时要加载(使动态库程序运行起来)
    • 与静态库的比较:
      • 由于静态库是将代码嵌入到使用程序中,多个程序使用时,会有多份代码,所以代码体积会增大。动态库的代码只需要存在一份,其他程序通过函数地址使用,所以代码体积小。
      • 静态库发生变化后,新的代码需要重新链接嵌入到执行程序中。动态库发生变化后,如果库中函数的定义(或地址)未变化,其他使用DLL的程序不需重新链接。
  2. 动态库的创建

    • 建立项目
    • 添加库程序
    • 库程序导出 (导出函数偏移地址)- 提供给使用者库中的函数等信息。
  3. 动态库的使用

    • 隐式链接(使动态库执行起来的过程不需要程序员负责,过程不明显)
    • 显式链接(使动态库程序运行起来的过程需要程序员自己负责)
  4. 动态库的函数

    • 实现动态库的函数
    • 库函数的导出
      • 声明导出
        使用 _declspec(dllexport) 在函数定义前面,导出函数
        注意:动态库编译链接后,也会有LIB文件,是作为动态库函数映射使用,与静态库不完全相同。
      • 模块定义文件 .def
        例如:
    		LIBRARY DLLFunc //库
    		EXPORTS         //库导出表
    		DLL_Mul	     @1	//导出的函数
    	     DLL_Sub     @2
    
  5. 制作动态库

    • 声明到处:_declspec(dllexport)将函数的偏移地址导到了dll的文件头中,如果是C++编译器,dll文件头中记录的是换名之后的函数对应的偏移地址
      lib文件记录的仅仅是换名之后的函数名对应的编号
    • 模块定义文件到处:将函数的偏移地址导出到了dll的文件头中,即便C++编译器,dll文件头中记录的是为换名的函数名对应的偏移地址
      lib文件中记录的仅仅是未换名的函数名对应的编号
    • 使用动态库:
    • 隐式链接---操作系统的加载负责使动态库执行(动态库的首地址)
      链接器负责到lib文件中抓函数的编号,程序执行起来后操作
      系统加载器负责拿着编号到dll文件中查询函数的偏移地址
    • 显示链接---程序员调用LoadLibrary使动态库执行
      程序员调用GetProcAddress()函数,在这个函数内部通过函
      数名称到dll文件头中查询函数的偏移地址
      例如:GetProcAddress(hDll, “CPPdll_add”);
  6. 库函数的使用

    1. 隐式链接
      • 头文件和函数原型
        可以在函数原型的定义前,增加declspec(dllimport), 例如
        _declspec(dllimport) int DLL_Add( ... );
        如果库函数使用C格式导出,需要在函数定义增加 extern “C”
      • 导入动态库的LIB文件
      • 在程序中使用函数
      • 隐式链接的情况,DLL可以存放的路径:
        *(1)与执行文件中同一个目录下-----推荐使用
        (2)当前工作目录
        *(3)Windows目录
        *(4)Windows/System32目录
        *(5)Windows/System
        (6)环境变量PATH指定目录
        注意:高版本VC的配置文件
    2. 显式链接
      • 定义函数指针类型 typedef
      • 加载动态库
    HMODULE LoadLibrary(
    	LPCTSTR lpFileName  //动态库文件名(.exe与.dll文件在同一路径下)或全路径
    ); 返回DLL的实例句柄(HMODULE 实际就是HINSTANCE)
    
     * 获取函数地址
    
    FARPROC GetProcAddress(
    	HMODULE hModule,    //DLL句柄
    	LPCSTR lpProcName   //函数名称
    ); 成功返回函数的绝对地址   返回地址DLL_ADD
    
     * 使用函数
     * 卸载动态库
    
    BOOL FreeLibrary(
    	HMODULE hModule   //DLL的实例句柄
    );
    

	3. 两种链接方式对比
		* 在库函数的定义不变情况下:
隐式链接,由于库函数地址是在程序编译链接时设置,所以当动态库变化后,使用程序需要重新编译链接。
显式链接,由于库函数地址是在程序执行时,动态的从库中查询,所以库变化后,不需要重新编译链接。				
		* 动态库加载
隐式链接,动态库是在程序启动时就被加载,当DLL不存在,程序无法启动
显式链接,动态库只在使用LoadLibrary函数,才会被加载。

7. DLL中类的使用
	* DLL中类的导出
在类名称前增加 _declspec(dllexport) 定义,例如:
	class _declspec(dllexport) CMath {};实际上是导出类的成员函数的函数名
通常使用预编译开关切换类的导入导出定义,例如:
	```
		#ifdef DLLCLASS_EXPORTS
		#define EXT_CLASS _declspec(dllexport)//DLL
		#else
		#define EXT_CLASS _declspec(dllimport)//使用者
		#endif
		class EXT_CLASS CMath{
	```

	* 使用DLL中的类
			* 导入DLL的LIb
			* 类的定义   CMath math;
			* 使用类       math.Add(…);
	* 动态库的程序入口
		入口程序不是DLL必须的。常用于DLL内部初始化或善后处理。
		```
		BOOL WINAPI DllMain(
			  HINSTANCE hinstDLL, //动态库实例句柄
			  DWORD fdwReason,    //被调用的原因
			  LPVOID lpvReserved   //保留值
		); 返回TRUE,表示动态库加载成功。
		```
		动态库的加载或卸载时会被调用。例如:使用LoadLibrary或FreeLibrary时会被调用。



	* DLLMAIN动态库入库函数
	```
	BOOL WINAPI DllMain(  
	HINSTANCE hinstDLL,  // handle to the DLL module
	  DWORD fdwReason,  // reason for calling function
	  LPVOID lpvReserved   // reserved
	);
	```


###windows文件

1. 创建或打开Windows文件
	```
	HANDLE CreateFile(
  	  LPCTSTR lpFileName, //文件名称(带盘符的全路径名)
	  DWORD dwDesiredAccess, //访问权限
	  DWORD dwShareMode,  //共享方式,读共享,即可以同时多个程序读,也可以允许别人删除,写等方式
	  LPSECURITY_ATTRIBUTES lpSecurityAttributes, 
	  	//安全属性,默认为NULL,windows下该属性基本都为NULL
	  DWORD dwCreationDisposition,  //创建或打开方式
	  DWORD dwFlagsAndAttributes, //文件属性
	  HANDLE hTemplateFile //文件句柄模板,默认为NULL,即为全双工
	);
	```
该函数既可以操作硬盘文件,也可以操作外围设备,如打印机
	成功返回文件句柄。相当于Unix中的文件描述符

	```
	DWORD dwShareMode,  //共享方式,读共享,即可以同时多个程序读,也可以允许别人删除,写等方式
	FILE_SHARE_DELETE---质询方式
	FILE_SHARE_READ---读共享
	FILE_SHARE_WRITE---写共享
	```
	```
	DWORD dwCreationDisposition,  //创建或打开方式
	CREATE_NEW---没有则新建,有则失败
	CREATE_ALWAYS---没有则新建,有则先删除再新建
	OPEN_EXISTING---有就打开,没有就失败
	OPEN_ALWAYS---有就打开,没有就创建然后再打开
	TRUNCATE_EXISTING---打开文件的同时,清空文件
	```

2. 写数据
	```	
		BOOL WriteFile(
		  HANDLE hFile, //文件句柄
		  LPCVOID lpBuffer, //数据BUFF
		  DWORD nNumberOfBytesToWrite, //数据长度
		  LPDWORD lpNumberOfBytesWritten, //返回实际写入的数据长度
		  LPOVERLAPPED lpOverlapped  //默认为NULL
		);
	```	
	
3. 读数据
	```
	BOOL ReadFile(
	  HANDLE hFile, //文件句柄
	  LPVOID lpBuffer,  //数据BUFF
	  DWORD nNumberOfBytesToRead,  //要读的字节数
	  LPDWORD lpNumberOfBytesRead, //实际读到字节数
	  LPOVERLAPPED lpOverlapped    //默认为NULL
	);
	```

4. 关闭文件
	```
		BOOL CloseHandle(
		  HANDLE hObject   //文件句柄
		);
	```
5. 文件长度
	```	
		DWORD GetFileSize(
		  HANDLE hFile, //文件句柄
		  LPDWORD lpFileSizeHigh  //返回文件长度的高32位
		); 返回值是文件长度的低32位
	```
DWOED就是无符号long类型,主要是为了方便存储大文件,函数返回值是以字节为单位,第二个参数以G为单位

6. 文件指针
	```	
		DWORD SetFilePointer(
		  HANDLE hFile, //文件句柄
		  LONG lDistanceToMove, //偏移量的低32位
		  PLONG lpDistanceToMoveHigh,  //偏移量的高32位
		  DWORD dwMoveMethod//偏移的相对位置
		); 
	```

	```
	DWORD dwMoveMethod//偏移的相对位置
	FILE_BEGIN
	FILE_CURRENT
	FILE_END
	```
	SetFilePointer函数返回实际偏移量的低32位,lpDistanceToMoveHigh返回实际偏移量的高32位


7. 文件相关操作
	CopyFile - 拷贝文件
	DeleteFile - 删除文件
	MoveFile - 移动文件

* 文件遍历
	1. 查找文件
	```
	HANDLE FindFirstFile(
	  LPCTSTR lpFileName, //查找路径
	  LPWIN32_FIND_DATA lpFindFileData  //查找的数据
	);  返回查找句柄
	```
	2. 获取下一个文件
	```
	BOOL FindNextFile(
	  HANDLE hFindFile, //查找句柄
	  LPWIN32_FIND_DATA lpFindFileData //查找的数据
	); 找到返回TRUE
	```
	3. 关闭查找

BOOL FindClose(
HANDLE hFindFile //查找句柄
);
```

文件操作实例

```
// WinFile.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "windows.h"
#include "stdio.h"
HANDLE hd;
void Create()
{

	hd=CreateFile(_T("d:/file.txt"),GENERIC_WRITE,
			FILE_SHARE_READ,NULL,CREATE_NEW,
			FILE_ATTRIBUTE_NORMAL,NULL
		);
}

void Write()
{

	char szText[] = "hello file";
	DWORD nLen = 0;
	WriteFile(hd, szText, strlen(szText), &nLen, NULL);
	printf("准备写入:%d,实际写入:%d\n", strlen(szText), nLen);
	//CloseHandle(hd);
}

void Read()
{
	char szText[256] = { 0 };
	DWORD nLen = 0;
	DWORD nHeigth = 0;
	DWORD nLow=GetFileSize(hd, &nHeigth);
	ReadFile(hd, szText, nLow, &nLen, NULL);
	printf("数据:%s,准备读取:%d,实际读取:%d\n",szText, nLow,nLen);

	CloseHandle(hd);

}

int main(int argc,char * argv[])
{
	Create();
	Write();
	Read();
	system("pause");
    return 0;
}
```
posted @ 2016-11-05 12:25  呉语伦比  阅读(161)  评论(0编辑  收藏  举报