win32第十四天

5.静态加载
1)使用动态库的程序通过链接动态库的导入库(.lib)获得所需要调用的函数入口地址。
2)动态库需要放在如下位置:
A.可执行程序所在目录 - 推荐使用
B.当前工程目录下 - 依赖于开发环境,用于调试
C.WINDOWS目录下                 \
D.WINDOWS/system32目录下  + 注意版本问题
E.WINDOWS/system目录下      /
F.PATH环境变量所包含的目录 - 依赖于系统环境


3)可执行程序一启动即加载所依赖的动态库,直到程序结束才卸载动态库。


6.动态加载(并不使用它的导入库)
HMODULE LoadLibrary (
  LPCTSTR lpFileName // 动态库路径
);
成功返回动态库实例句柄,失败返回NULL。
FARPROC GetProcAddress (
  HMODULE hModule,      // 动态库实例句柄
  LPCSTR      lpProcName // 函数名
);
成功返回函数地址,失败返回NULL。
1)函数名需要考虑C++换名问题。
2)函数指针的类型问题。
BOOL FreeLibrary (
  HMODULE hModule  // 动态库实例句柄
);
成功返回TRUE,失败返回FALSE。
QQ在升级的时候需要退出,是因为它是使用的静态库加载,而如果使用动态库的话则不需要退出程序就可以在线升级。
1.工程名:LoadDLL
#include<windows.h>
#include<stdio.h>
int main(){
HMODULE hDLL=NULL;
hDLL=LoadLibrary("F:/Win32/Day14/Bin/CDll.dll");
if(hDLL==NULL)
fprintf(stderr,"加载动态库失败!%u\n",GetLastError());
FreeLibrary(hDLL);
return 0;
}
//打印出错误信息
void PrintLastError(LPCSTR pszTitle,BOOL bConsole=TRUE,HWND hWnd=NULL){
LPVOID pvErrMsg=NULL;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,NULL,GetLastError(),MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED),(LPSTR)&pvErrMsg,0,NULL);
if(bConsole)
fprintf(stderr,"%s:%s\n",pszTitle,(LPCSTR)pvErrMsg);
else
MessageBox(hWnd,(LPCSTR)pvErrMsg,pszTitle,MB_OK);
///释放
LocalFree(pvErrMsg);
}
///继续在main函数中, 获得函数地址
PFUNC2 pfunc=NULL;
if(!(pfunc=(PFUNC2)GetProcAddress(hDll,"c_mul"))){
PrintLastError("GetProcAddress出错");
return -1;
}
typedef int (*PFUNC2)(int ,int);
printf("%d*%d=%d\n",a,b,pfunc(a,b));
一、动态库的入口
动态库的入口不是必须的,常用于对动态库的内部状态做初始化。
BOOL WINAPI DllMain (
  HANDLE hInstance,    // 动态库实例句柄
  DWORD dwReason,   // 被调用原因
  LPVOID  lpvReserved // 保留
);
成功返回TRUE,失败返回FALSE。
dwReason取值:
DLL_PROCESS_ATTACH - 进程加载,主线程中调用LoadLibrary
DLL_PROCESS_DETACH - 进程卸载,主线程中调用FreeLibrary
DLL_THREAD_ATTACH - 线程加载,子线程中调用LoadLibrary
DLL_THREAD_DETACH - 线程卸载,子线程中调用FreeLibrary
/
动态库:DllMain
#include<windows.h>
#include<stdio.h>
#include "DllMain.h"
BOOL WINAPI DllMain(HANDLE hInstance,DWORD dwReason,LPVOID lpvReserved){
switch(dwReason){
case DLL_PROCESS_ATTACH:
printf("进程加载");
break;
case DLL_PROCESS_DETACH:
printf("进程卸载");
break;
}
return TRUE;
}
void hello(){
printf("你好,我是快乐的动态库");
}
/DllMain.h
#ifndef _DLLMAIN_H
#define _DLLMAIN_H
#ifdef DLLMAIN_EXPORTS
#define DLLMAIN_API _declspec(dllexport)
#else
#define DLLMAIN_API _declspec(dllimport)
#endif
DLLMAIN_API void hello(void);
#endif;
//写个程序加载下这个库
#include "../DLLMain/DllMain.h"
#pragma comment(lib,"../Lib/DllMain.lib")
int main(void){
hello();
return 0;
}
动态加载
#include "../DLLMain/DllMain.h"
//#pragma comment//(lib,"../Lib/DllMain.lib")
int main(void){
HMODULe hDll=LoadLibrary("DllMain.dll");
if(!hDll){
PrintLastError("LoadLibrary出错");
return -1;
}
PHELLO phello=(PHELLO)GetProcAddress(hDll,"?hello@@YAXXZ");
if(!phello){
PrintLastError("GetProcAddress出错");
}
phello();
FreeLibrary(hdll);
return 0;
}

C++函数中注意换名问题。这个名称哪里可以看到呢。暂时未知。有待以后查看。
/


二、Windows文件系统
Windows的常见文件系统:FAT、FAT32、NTFS
磁道:由若干扇区组成
扇区:512字节
固态硬盘:就是一个大U盘
文件系统的最小管理单位——簇——连续的若干扇区
FAT32:1簇=32扇区=16K字节
NTFS:1簇=8扇区=4K字节
文件存储是以簇为单位占用磁盘空间,即使只有1个字节,也要占用1个簇的磁盘空间。
三、目录APIs
1.获取磁盘驱动器信息
DWORD GetLogicalDrives (void);
返回当前可用逻辑驱动器的掩码。
L--------------------------------------------->H
XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
HGFEDCBA           ...KJI
0:无此逻辑驱动器
1:有此逻辑驱动器
DWORD表示32位,故可最多划分32个逻辑驱动器。使用小端方式存储。
///
WinDir.cpp
#include<windows.h>
#include<stdio.h>
int main(){
DWORD dwDrvs=GetLogicalDrives();
for(int i=0;i<sizeof(DWORD)*8,i++){
if(dwDrvs&1<<i)
printf("%c ",'A'+i);
printf("\n");
}
}
///
2.获取系统驱动器
DWORD GetLogicalDriveStrings (
  DWORD nBufferLength, // 缓冲区大小(以字符为单位)
  LPTSTR  lpBuffer            // 缓冲区指针
);
成功返回字符串长度,失败返回0。
///
cout<<"系统驱动器:";
CHAR szSysDrv[256];
GetLogicalDriveStrings(sizeof(szSysDrv)/sizeof(szSysDrv[0]),szSysDrv);
cout<<szSysDrv;

3.获取当前目录
DWORD GetCurrentDirectory (
  DWORD nBufferLength, // 缓冲区大小(以字符为单位)
  LPTSTR  lpBuffer            // 缓冲区指针
);
成功返回字符串长度,失败返回0。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@/
cout<<"原当前目录:";
CHAR szCurDir[MAX_PATH+1];//加'/0'
GetCurrentDirectory(sizeof(sszCurDir)/sizeof(szCurDir[0]),szCurDir);
cout<<szCurDir;
SetCurrentDirectory("C:/");
cout<<"新当前目录:";
GetCurrentDirectory(sizeof(sszCurDir)/sizeof(szCurDir[0]),szCurDir);
cout<<szCurDir;

4.设置当前目录
BOOL SetCurrentDirectory (
  LPCTSTR lpPathName // 当前目录
);
成功返回TRUE,失败返回FALSE。


5.获取WINDOWS目录
UINT GetWindowsDirectory (
  LPSTR lpBuffer, // 缓冲区指针
  UINT   uSize     // 缓冲区大小(以字符为单位)
);
成功返回字符串长度,失败返回0。
6.获取系统(system32)目录
UINT GetSystemDirectory (
  LPSTR lpBuffer, // 缓冲区指针
  UINT   uSize     // 缓冲区大小(以字符为单位)
);
成功返回字符串长度,失败返回0。
//
printf ("WINDOWS目录:");
CHAR szWinDir[MAX_PATH+1];
GetWindowsDirectory (szWinDir,
sizeof (szWinDir) / sizeof (szWinDir[0]));
printf ("%s\n", szWinDir);
printf ("系统目录:");
CHAR szSysDir[MAX_PATH+1];
GetSystemDirectory (szSysDir,
sizeof (szSysDir) / sizeof (szSysDir[0]));
printf ("%s\n", szSysDir);
printf ("临时目录:");
CHAR szTempDir[MAX_PATH+1];
GetTempPath (sizeof (szTempDir) / sizeof (szTempDir[0]),szTempDir);
printf ("%s\n", szTempDir);
///
7.获取临时路径
DWORD GetTempPath (
  DWORD nBufferLength, // 缓冲区大小(以字符为单位)
  LPTSTR  lpBuffer            // 缓冲区指针
);
成功返回字符串长度,失败返回0。
8.创建目录
BOOL CreateDirectory (
  LPCTSTR lpPathName, // 目录路径
  LPSECURITY_ATTRIBUTES lpSecurityAttributes // 安全属性,上层应用中置NULL
);
成功返回TRUE,失败返回FALSE。
9.移动目录
BOLL MoveFile (
  LPCTSTR lpExistingFileName, // 原路径
  LPCTSTR lpNewFileName       // 新路径
);
成功返回TRUE,失败返回FALSE。
注意:不能跨逻辑驱动器移动目录,但是可以跨逻辑驱动器移动文件。
10.删除空目录
BOOL RemoveDirectory (
  LPCTSTR lpPathName // 目录路径
);
成功返回TRUE,失败返回FALSE。
四、文件APIs
1.创建/打开文件
HANDLE CreateFile (
  LPCTSTR lpFileName,          // 文件路径
  DWORD dwDesiredAccess, // 访问方式
  DWORD dwShareMode,     // 共享方式
  ...                                        // 安全属性,NULL
  DWORD dwCreationDisposition, // 创建或打开方式
  DWORD dwFlagsAndAtrributes,  // 文件属性
  HANDLE hTemplateFile               // 句柄模板(磁盘文件,设NULL)
);
成功返回文件句柄,失败返回INVALID_HANDLE_VALUE(-1)
dwDesiredAccess:
0 - 质询(判断文件是否存在)
GENERIC_READ - 读取
GENERIC_WRITE - 写入
dwShareMode:
FILE_SHARE_DELETE - 允许其它进程删除此文件
FILE_SHARE_READ    - 允许其它进程读取此文件
FILE_SHARE_WRITE  - 允许其它进程写入此文件
dwCreationDisposition:
CREATE_NEW - 不存在就创建,已存在就失败
CREATE_ALWAYS - 不存在就创建,已存在就删除原文件再创建
OPEN_EXISTING - 已存在就打开,不存在就失败
OPEN_ALWAYS - 已存在就打开,不存在就创建新文件再打开
TRUNCATE_EXISTING - 已存在就先清空再打开,不存在就失败


2.关闭文件
BOOL CloseHandle (
  HANDLE handle // 内存对象句柄
);
成功返回TRUE,失败返回FALSE。
3.写入文件
BOOL WriteFile (
  HANDLE     hFile,      // 文件句柄
  LPCVOID    lpBuffer, // 数据缓冲区
  DWORD     nNumberOfBytesToWrite,  // 期望写入的字节数
  LPDWORD  lpNumberOfBytesWritten, // 实际写入的字节数
  LPOVERLAPPED lpOverlapped // 异步传输结构,可为NULL
);
成功返回TRUE,失败返回FALSE。
4.获取文件大小
DWORD GetFileSize (
  HANDLE     hFile,              // 文件句柄
  LPDWORD lpFileSizeHigh // 文件字节数的高32位 
);
成功返回文件字节数的低32位。
32位 - 4G
64位 - 16G
5.读取文件
BOOL ReadFile (
  HANDLE     hFile,              // 文件句柄
  LPVOID      lpBuffer,         // 数据缓冲区
  DWORD     nNumberOfBytesToRead, // 期望读取的字节数
  LPDWORD lpNumberOfBytesRead,    // 实际读取的字节数  
  LPOVERLAPPED lpOverlapped // 异步传输结构,可为NULL
);
成功返回TRUE,失败返回FALSE。
6.设置文件指针
DWORD SetFilePointer (
  HANDLE hFile,                              // 文件句柄
  LONG     lDistanceToMove,          // 偏移量的低32位
  PLONG   lpDistanceToMoveHigh, // 偏移量的高32位(输入输出)
  DWORD dwMoveMethod             // 偏移相对位置
);
返回文件指针新位置的低32位(高32位通过lpDistanceToMoveHigh输出)。
dwMoveMethod取值:
FILE_BEGIN
FILE_CURRENT
FILE_END
五、拷贝、移动、删除APIs
1.拷贝文件
BOOL CopyFile (
  LPCTSTR lpExistingFileName, // 源路径
  LPCTSTR lpNewFileName,      // 目标路径
  BOOL      bFailIfExists             // TRUE存在就失败,FALSE存在就覆盖
);
成功返回TRUE,失败返回FALSE。
2.移动文件
BOOL MoveFile (
  LPCTSTR lpExistingFileName, // 原路径
  LPCTSTR lpNewFileName       // 新路径
);
成功返回TRUE,失败返回FALSE。
注意:不能跨逻辑驱动器移动目录,但是可以跨逻辑驱动器移动文件。
3.删除文件
BOOL DeleteFile (
  LPCTSTR lpFileName // 路径
);
成功返回TRUE,失败返回FALSE。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值