Windows程序设计5(MDI、库程序、文件)

 

1、 多文档界面(MDI)

  1. MDI的组成

MDI主窗口(主框架窗口MainFrame

MDI客户窗口(MDICLIENT

MDI 子窗口1

MDI 子窗口2

…….

  1. 创建过程

1)创建MDI主窗口

    a) 没有父窗口,需要注册窗口类,定义窗口过程函数

b) MDI主窗口的窗口过程函数,不再调用DefWindowProc。代之以调用DefFramProc

  LRESULT   DefFrameProc(

  HWND  hWnd,           // handle to MDI frame window

  HWND  hWndMDIClient,  // handle to MDI client window

  UINT  uMsg,           // message

  WPARAM  wParam,       // first message parameter

  LPARAM  lParam        // second message parameter

);

2) 创建MDI客户窗口

A. 窗口类:MDI主窗口

B.父窗口是MDI主窗口

C.创建时需要使用CLIENTCREATRUCT结构,指定MDI子窗口的起始ID

3)创建MDI子窗口

A. 父窗口是MDI客户窗口

B.所有的MDI子窗口都需要注册并定义窗口过程函数

CMDI子窗口的窗口函数过程函数,不再调用DefWindProc。代之以调用DefMDIChildProc

4)相关函数:

DrawMenuBar(HWND hwnd);//重绘指定窗口菜单栏,用于切换多文档时刷新重绘相应菜单栏。

EnumChildWindows();//枚举指定窗口的所有子窗口执行lpEnumFunc回调函数。

BOOL  EnumChildWindows(

   HWND   hWndParent,         // handle to parent window

   WNDENUMPROC  lpEnumFunc,  // pointer to callback function

   LPARAM   lParam            // application-defined value

);

SetWindowLong/ GetWindowLong;

IsWindow;等等

5)消息相关:

WM_MDIACTIVATE

WM_MDIDESTROY

WM_MDIGETACTIVE

WM_MDICASCADE

WM_MDITILE

WM_MDIICONARRANGE

2、 Windows库程序

1. 分类:

静态库程序 - 运行时不依赖,在链接阶段会被链接到可执行文件或者动态库中,本质是目标文件程序的归档。文件扩展名:LIB

 

动态库程序 - 运行时依赖,在链接阶段不会被复制到可执行文件或其他动态库中。文件扩展名:DLL

 

  1. 静态库程序

所有的win32函数都没有静态库版本,但标准C/C++函数既有静态库也有动态库版本。可以在工程选项中配置。

C语言静态库

1 静态库的使用

建立一个C文件,可以在文件中直接使用C库函数,不需要头文件。C编译器只是根据库函数名称,在库中找到对应的函数代码,进行链接。

2 静态库的创建

1)建项目

2)添加库程序(),编写源文件代码使用C文件

3 链接静态库的路径设置

1)项目的“project/ Setting”中设置库的路径

2)可以使用pragma关键字设置#pragma comment( lib, "..\\lib\\clib.lib")(指定路径)

C++语言的静态库

1. 静态库的建立

1)建立项目

2)添加库程序,源文件使用CPP文件

2. 库的导入

1)项目的“Setting”中设置库的路径

2)可以使用 pragma 关键字设置

3. 注意

CPP环境使用C静态库,库中函数原型定义要增加 extern “C”, 例如:extern "C" int Add(... ); extern “C” {#include “myc.h”}.等。防止C++编译器对C语言库函数做换名,使得采用C下的函数原型,正确调用C库函数。C中使用C++库时,需要在C++库编译时,对extern “C” {  } c++编译器宏#ifdef _ _cplusplus 来处理(由于C语言中无法识别 extern "C"  串。)。使得可对C编译器与C++编译器公用。

如:#ifdef  __cplusplus  

extern "C" {

#endif

int Add(... );

#ifdef  __cplusplus

}

#endif

  1. 动态库的程序

1. 与静态库的比较:

1)由于静态库是将代码嵌入到使用程序中,多个程序使用时,会有多份代码,所以代码体积会增大。动态库的代码只需要存在一份,其他程序通过函数地址使用,所以代码体积小。

 2)静态库发生变化后,新的代码需要重新链接嵌入到执行程序中。动态库发生变化后,如果库中函数的定义(或地址)未变化,其他使用DLL的程序不需重新链接。

2. 动态库的创建

1 ) 建立项目

2 ) 添加库程序

3 ) 库程序导出  提供给使用者库中的函数等信息。

3 动态库的使用

3.1 隐式链接

3.2 显式链接

4 动态库的函数

4.1 实现动态库的函数

4.2 库函数的导出

1C++的导出

使用 _ _declspec(dllexport) 导出函数

注意:动态库编译链接后,也会有LIB文件,是作为动态库函数映射使用,与静态库不完全相同,另外也要加载它。

2C的导出方式     extern “C” _ _ declspec(dllexport)  int  Sub(...);

3)导入: _ _declspec(dllimport) 导出函数.。一般VC6.0自动导入,无需自己做

4)若不用dllexport导出,可定义模块定义文件(.def)来导出。

例如:

EXPORTS    //库导出表

Sub //导出的函数名

4.3 库函数的使用

     4.3.1 隐式链接

1)头文件和函数原型

可以在函数原型的定义前,增加declspec(dllimport) 例如

_declspec(dllimport) int DLL_Add( ... );

如果库函数使用C格式导出,需要在函数定义增加 extern “C”

2)导入动态库的LIB文件

3)在程序中使用函数

4)隐式链接的情况,DLL可以存放的路径:

1)与执行文件中同一个目录下  推荐使用

2)当前工作目录     依赖开发环境,用于调试

3Windows目录   注意版本问题

4Windows/System32目录      注意版本问题

5Windows/System   注意版本问题

6)环境变量PATH指定目录 依赖与系统环境

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

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{

...

};

4.3.2 动态加载HMODULE LoadLibrary(

LPCTSTR lpFileName  //动态库文件名或全路径

); 返回DLL的实例句柄(HINSTANCE

1)获取函数地址

FARPROC   GetProcAddress(

HMODULE   hModule,    //DLL句柄

LPCSTR    lpProcName   //函数名称

); 成功返回函数地址,失败返回NULL

a. 函数名需要注意C++换名问题

b. 函数指针的类型问题,要强制转换函数指针类型,参数等,可用typedef  type  (*fun)(type  a, type b  ,…)

2)使用函数

3)卸载动态库

BOOL   FreeLibrary(

HMODULE  hModule   //DLL的实例句柄

);//成功返回TRUE,失败返回FALSE

       注意:高版本VC的配置文件

4.3.3 两种链接方式对比

1)在库函数的定义不变情况下:

隐式链接,由于库函数地址是在程序编译链接时设置,所以当动态库变化后,使用程序需要重新编译链接。

显式链接,由于库函数地址是在程序执行时,动态的从库中查询,所以库变化后,不需要重新编译链接。

2)动态库加载

隐式链接,动态库是在程序启动时就被加载,当DLL不存在,程序无法启动

显式链接,动态库只在使用LoadLibrary函数,才会被加载。

动态库的程序入口:

入口程序不是DLL必须的。常用于DLL内部初始化或善后处理。

BOOL  WINAPI  DllMain(

   HINSTANCE  hinstDLL, //动态库实例句柄

   DWORD  fdwReason,    //被调用的原因

    LPVOID  lpvReserved   //保留值

); 返回TRUE,表示动态库加载成功。失败返回FALSE

动态库的加载或卸载时会被调用。例如:使用LoadLibraryFreeLibrary时会被调用。

fdwReason 参数说明:

DLL_PROCESS_ATTACH   进程加载  主线程中调用LoadLibrary

DLL_THREAD_ATTACH   线程链接  子线程中调用LoadLibrary

DLL_THREAD_DETACH   线程卸载  子线程中调用FreeLibrary

DLL_PROCESS_DETACH  进程卸载   主线程中调用FreeLibrary

3、 Windows  文件系统

  1. Windows常见文件系统

操作系统管理磁盘数据的方式。

FATFAT32NTFS

硬盘的管理

磁道:包括若干个扇区

扇、扇区: - 大小为512字节

文件系统最小管理单位   - 由连续的几个扇区组成8/16/32/64

FAT32  - 132扇区.16K字节

NTFS   - 18扇区即4K字节

文件存储时,是以簇为单位占用硬盘空间,

即使文件只有1个字节,也要占用1簇的空间。故一般下,NTFSFAT32占有有效空间更多,浪费更少。

  1. Windows 目录相关API函数

1) 获取磁盘驱动器信息

DWORD  GetLogicalDrives(void );//返回当前可用逻辑驱动器的掩码。

磁盘表示与掩码关系:

L-----------------------------------------------------------------àH

XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX

HGFEDCBA     ……KJI

0:表示无此驱动器

1:表示存在此驱动器

2) 获取系统驱动器

DWORD GetLogicalDriveStrings(

    DWORD nBufferLength,  // 缓冲区大小(以字符为单位)

    LPTSTR lpBuffer       // 返回指向系统驱动器缓冲区字符串

);//成功返回串长度,失败返回0.

3) 获取当前工作目录

DWORD   GetCurrentDirectory(

DWORD   nBufferLength,  // 缓冲区大小(以字符为单位)

LPTSTR   lpBuffer       // 缓冲区指针

);//成功返回缓冲区串长度,失败返回0

4) 设置当前工作目录

 BOOL   SetCurrentDirectory(

 LPCTSTR   lpPathName   //指定新的工作路径

);//成功返回非0值,失败返回0.

5) 获取Windows 目录

UINT   GetWindowsDirectory(

LPTSTR   lpBuffer,  //  指向缓冲区的指针

UINT   uSize        // 目录缓冲区大小(以字符为单位)

);//成功返回字符串长度,失败返回0

6) 获取系统目录

UINT    GetSystemDirectory(

    LPTSTR    lpBuffer,  //指向缓冲区的指针

   UINT   uSize        //缓冲区目录的大小

);///成功返回字符串长度,失败返回0

6) 获取临时文件目录

DWORD    GetTempPath(

   DWORD    nBufferLength,  // 缓冲区大小(以字符为单位)

   LPTSTR    lpBuffer       // 缓冲区指针

);//成功返回字符串长度,失败返回0

7) 目录创建

BOOL   CreateDirectory(

   LPCTSTR    lpPathName,//目录名称

   LPSECURITY_ATTRIBUTES  lpSecurityAttributes//安全属性默认为NULL

);//成功返回非0值,失败返回0。当目录文件已存在,无法创建该文件。

8)目录删除

BOOL    RemoveDirectory(

LPCTSTR    lpPathName  //目录名称

);成功返回true,失败返回false。只能删除空目录,若内有文件则无法删除。

9) 目录修改/ 移动

BOOL   MoveFile(

LPCTSTR    lpExistingFileName, //当前的名称

LPCTSTR lpNewFileName   //新的名称

);//成功返回true,失败返回false

///当新目录或文件已存在,无法移动或更改该目录或文件。

////注意:不能跨逻辑驱动器移动目录,但是可以跨逻辑驱动器移动文件。

  1. Windows  文件相关API

1) 创建或打开文件

HANDLE   CreateFile(

  LPCTSTR  lpFileName, //文件名称

  DWORD  dwDesiredAccess, //访问权限,方式

  DWORD  dwShareMode,   //共享方式

  LPSECURITY_ATTRIBUTES lpSecurityAttributes,//安全属性默认NULL

  DWORD  dwCreationDisposition,  //创建或打开方式

  DWORD  dwFlagsAndAttributes,  //文件属性

  HANDLE  hTemplateFile //文件句柄模板(磁盘文件,默认为NULL)

); //成功返回文件句柄,失败返回INVALID_HANDLE_VALUE(-1)

小记:CreateFile 可以创建或打开以下文件:

files   文件

pipes   管道

mailslots  邮槽

communications resources  通信资源

disk devices (Windows NT only)  磁盘驱动

consoles   控制台

directories (open only) 目录

参数说明:

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_EXITSTING 已存在先清空再打开,不存在则失败

2) 关闭文件

BOOL    CloseHandle(

  HANDLE   hObject   //句柄

);//成功返回true,失败返回false

小记:CloseHandle()也可以关闭其他的。

如下:

  • Communications device
  • Console input
  • Console screen buffer
  • Event
  • File
  • File mapping
  • Job
  • Mailslot
  • Mutex
  • Named pipe
  • Process
  • Semaphore
  • Socket
  • Thread
  • Token

3) 写入数据

BOOL    WriteFile(

  HANDLE   hFile, //文件句柄

  LPCVOID   lpBuffer, //数据BUFF

  DWORD   nNumberOfBytesToWrite, //期望写入数据字节数

  LPDWORD   lpNumberOfBytesWritten, //返回实际写入的数据字节数

  LPOVERLAPPED  lpOverlapped  //异步传输结构,默认为NULL

);///成功返回true,失败返回false

4) 读出数据

BOOL   ReadFile(

  HANDLE   hFile, //文件句柄

  LPVOID   lpBuffer,  //数据BUFF

  DWORD   nNumberOfBytesToRead,  //要读的字节数

  LPDWORD   lpNumberOfBytesRead, //实际读到字节数

  LPOVERLAPPED   lpOverlapped    //异步传输结构,默认为NULL

);///成功返回true,失败返回false

5) 获取文件大小(字节数)

DWORD   GetFileSize(

  HANDLE  hFile, //文件句柄

  LPDWORD  lpFileSizeHigh  //文件字节数的高32

); 返回值是文件字节数的低32

///64位系统下,需要将高32位和低32位组合为64位的,得到实际文件大小,

////而在32为系统下,无需考虑高32位的。

6) 移动文件指针

DWORD    SetFilePointer(

  HANDLE   hFile, //文件句柄

  LONG    lDistanceToMove, //字节偏移量的低32

  PLONG    lpDistanceToMoveHigh,  //返回实际字节偏移量的高32

  DWORD    dwMoveMethod//偏移的相对位置

); //返回文件指针实际新的位置字节偏移量的低32位,

///对于高32位情况同GetFileSize()若不要高32位且若后移,则应该设置高32NULL,否则可能失败。纵使设置相应高32位为NULL指针变量也不行。其他情况下无要求。

dwMoveMethod  参数说明:

FILE_BEGIN     文件开始位置

FILE_CURRENT  文件当前位置

FILE_END       文件末尾位后一个位置

7) 文件其他相关

复制文件:

BOOL    CopyFile(

  LPCTSTR   lpExistingFileName, // 源文件

  LPCTSTR   lpNewFileName,  // 复制的目标文件

  BOOL   bFailIfExists      // flag for operation if file exists

);//

// bFailIfExists 参数说明:

若为true,则若复制相同位置、名文件,则返回失败。

若为false,则若复制相同位置、名文件,则覆盖返回成功。

删除文件:

BOOL   DeleteFile(

  LPCTSTR    lpFileName   //删除的文件名

);//成功返回true,失败返回false

移动文件:同移动目录的MoveFile()

8) 文件属性

获取文件属性:

DWORD   GetFileAttributes(

     LPCTSTR   lpFileName   //文件名或目录名

);///成功返回指定文件的属性,失败则返回0xFFFFFFFF。

获取文件属性、时间等:

BOOL GetFileAttributesEx(

 LPCTSTR lpFileName,        // 目录或文件名

 GET_FILEEX_INFO_LEVELS  fInfoLevelId, //设置获取文件或目录属性

  LPVOID lpFileInformation   // 由fInfoLevelId指定的属性而获取的文件或目录属性信息缓冲区

);////成功返回true,失败返回false

//////fInfoLevelId参数说明:(枚举类型结构),

其枚举值:GetFileExInfoStandard。

由结构体WIN32_FILE_ATTRIBUTE_DATA返回其值。

typedef struct _WIN32_FILE_ATTRIBUTE_DATA{

   DWORD     dwFileAttributes; //文件属性

   FILETIME  ftCreationTime; //创建时间

   FILETIME  ftLastAccessTime; //最近访问时间

   FILETIME   ftLastWriteTime; //最近写入时间

   DWORD   nFileSizeHigh; //文件高32位字节数

   DWORD   nFileSizeLow; //文件低32位字节数

}

WIN32_FILE_ATTRIBUTE_DATA, *LPWIN32_FILE_ATTRIBUTE_DATA;

/// FILETIME结构体

typedef struct _FILETIME { // ft

    DWORD dwLowDateTime; //低32位日期

    DWORD dwHighDateTime; //高32位日期

} FILETIME;

另外可用FileTimeToSystemTime转化为系统时间,

BOOL FileTimeToSystemTime(

  CONST FILETIME *lpFileTime,//转变的文件时间

  LPSYSTEMTIME lpSystemTime,// 接收的系统时间

   );

SYSTEMTIME(结构体):见MSDN

设置文件属性:

BOOL    SetFileAttributes(

  LPCTSTR    lpFileName,      // 文件名

  DWORD    dwFileAttributes   //设置文件属性,可组合设置

);///成功返回true,失败返回false

增加文件属性:获取原文件属性,与需要增加的属性做位或,再设置回去。

删除文件属性:获取原文件属性,与需要删除的属性取反且位与,再设置回去。

9) 文件查找

HANDLE   FindFirstFile(

   LPCTSTR    lpFileName, //查找路径

   LPWIN32_FIND_DATA    lpFindFileData  //查找的数据

);  //返回查找句柄,此句柄可用于findnextfile,findclose,失败返回INVALID_HANDLE_VALUE 

参数说明:LPWIN32_FIND_DATA(结构体),保存查找文件或子目录的数据

typedef  struct _WIN32_FIND_DATA { // wfd

    DWORD    dwFileAttributes;   //文件属性

    FILETIME   ftCreationTime;   //创建时间

    FILETIME   ftLastAccessTime; ///最后访问时间

    FILETIME   ftLastWriteTime; ///最后写入时间

    DWORD    nFileSizeHigh; //文件字节数高32

    DWORD    nFileSizeLow; ///文件字节数低32

DWORD    dwReserved0; //

DWORD    dwReserved1;   //保留

    TCHAR    cFileName[ MAX_PATH ]; //文件名

    TCHAR    cAlternateFileName[ 14 ]; ///可选文件名

} WIN32_FIND_DATA;

10) 获取下一个文件

BOOL    FindNextFile(

  HANDLE   hFindFile, //查找句柄,

  LPWIN32_FIND_DATA   lpFindFileData //查找的数据

); //找到返回TRUE,失败返回FALSE。,查找基于文件名

11) 关闭查找

BOOL FindClose (

HANDLE  hFindFile  // 查找句柄

);//成功返回TRUE,失败返回FALSE

猜你喜欢

转载自www.cnblogs.com/haomiao/p/11646585.html