/*---------------------------------------
POPPAD.C
-- Popup Editor
(c) Charles Petzold, 1998
---------------------------------------*/
#include <windows.h>
#include <commdlg.h> //使用通用对话框,必须包含此头文件
#include "resource.h" //资源文件
#define EDITID
1
#define UNTITLED
TEXT ("(untitled)
")
LRESULT CALLBACK WndProc
(HWND, UINT, WPARAM, LPARAM) ;
BOOL CALLBACK AboutDlgProc
(HWND, UINT, WPARAM, LPARAM) ;
// Functions in POPFILE.C
void PopFileInitialize
(HWND) ;
BOOL PopFileOpenDlg
(HWND, PTSTR, PTSTR) ;
BOOL PopFileSaveDlg
(HWND, PTSTR, PTSTR) ;
BOOL PopFileRead
(HWND, PTSTR) ;
BOOL PopFileWrite
(HWND, PTSTR) ;
// Functions in POPFIND.C
HWND PopFindFindDlg
(HWND) ;
HWND PopFindReplaceDlg
(HWND) ;
BOOL PopFindFindText
(HWND, int *, LPFINDREPLACE) ;
BOOL PopFindReplaceText
(HWND, int *, LPFINDREPLACE) ;
BOOL PopFindNextText
(HWND, int *) ;
BOOL PopFindValidFind
(void) ;
// Functions in POPFONT.C
void PopFontInitialize
(HWND) ;
BOOL PopFontChooseFont
(HWND) ;
void PopFontSetFont
(HWND) ;
void PopFontDeinitialize
(void) ;
// Functions in POPPRNT.C
BOOL PopPrntPrintFile
(HINSTANCE, HWND, HWND, PTSTR) ;
// 全局变量
static HWND hDlgModeless ;
static TCHAR szAppName[] = TEXT ("PopPad
") ;
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
MSG msg ;
HWND hwnd ;
HACCEL hAccel ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW
| CS_VREDRAW
;
wndclass.lpfnWndProc = WndProc
;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon
(hInstance, szAppName) ; //自定义图标
wndclass.hCursor = LoadCursor
(NULL
, IDC_ARROW
) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject
(WHITE_BRUSH
) ;
wndclass.lpszMenuName = szAppName ; //自定义菜单
wndclass.lpszClassName = szAppName ;
if (!RegisterClass
(&wndclass))
{
MessageBox
(NULL
, TEXT ("This program requires Windows NT!
"),
szAppName, MB_ICONERROR
) ;
return 0 ;
}
hwnd = CreateWindow
(szAppName, NULL
, //初始时窗口标题栏无文字
WS_OVERLAPPEDWINDOW
,
CW_USEDEFAULT
, CW_USEDEFAULT
,
CW_USEDEFAULT
, CW_USEDEFAULT
,
NULL
, NULL
, hInstance, szCmdLine) ;
ShowWindow
(hwnd, iCmdShow) ;
UpdateWindow
(hwnd) ;
//加载快捷键资源到内存
hAccel = LoadAccelerators
(hInstance, szAppName) ;
while (GetMessage
(&msg, NULL
, 0, 0))
{
//拦截非模态对话框消息
if (hDlgModeless == NULL
|| !IsDialogMessage
(hDlgModeless, &msg))
{
//拦截快捷键消息
if (!TranslateAccelerator
(hwnd, hAccel, &msg))
{
TranslateMessage
(&msg) ;
DispatchMessage
(&msg) ;
}
}
}
return msg.wParam ;
}
void DoCaption
(HWND hwnd, TCHAR * szTitleName)
{
TCHAR szCaption[64 + MAX_PATH
] ;
//将窗口名和打开的文件路径拼接起来,如果未打开任何文件则显示(UNTITLED)
wsprintf
(szCaption, TEXT ("%s - %s
"), szAppName,
szTitleName[0] ? szTitleName : UNTITLED
) ;
//向标题栏写入文字
SetWindowText
(hwnd, szCaption) ;
}
void OkMessage
(HWND hwnd, TCHAR * szMessage, TCHAR * szTitleName)
{
TCHAR szBuffer[64 + MAX_PATH
] ;
//拼接提示字符串
wsprintf
(szBuffer, szMessage, szTitleName[0] ? szTitleName : UNTITLED
) ;
//弹出消息提示窗口
MessageBox
(hwnd, szBuffer, szAppName, MB_OK
| MB_ICONEXCLAMATION
) ;
}
short AskAboutSave
(HWND hwnd, TCHAR * szTitleName)
{
TCHAR szBuffer[64 + MAX_PATH
] ;
int iReturn ;
wsprintf
(szBuffer, TEXT ("Save current changes in %s?
"),
szTitleName[0] ? szTitleName : UNTITLED
) ;
//弹出提示消息,是否保存文件。返回用户选择
iReturn = MessageBox
(hwnd, szBuffer, szAppName,
MB_YESNOCANCEL
| MB_ICONQUESTION
) ;
if (iReturn == IDYES
) //如果用户选择的YES,就向父窗口发送保存消息
//如果消息执行失败,根据程序设计,返回0,则将用户选择设为CANCEL
if (!SendMessage
(hwnd, WM_COMMAND
, IDM_FILE_SAVE
, 0))
iReturn = IDCANCEL
;
//返回用户选择
return iReturn ;
}
LRESULT CALLBACK WndProc
(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL bNeedSave = FALSE
;
static HINSTANCE hInst ;
static HWND hwndEdit ;
static int iOffset ;
static TCHAR szFileName[MAX_PATH
], szTitleName[MAX_PATH
] ;
static UINT messageFindReplace ;
int iSelBeg, iSelEnd, iEnable ;
LPFINDREPLACE pfr ;
switch (message)
{
case WM_CREATE
:
//取得程序执行实例句柄
hInst = ((LPCREATESTRUCT) lParam) -> hInstance ;
//创建编辑控件的子窗口,ID为 EDITID
hwndEdit = CreateWindow
(TEXT ("edit
"), NULL
,
WS_CHILD
| WS_VISIBLE
| WS_HSCROLL
| WS_VSCROLL
|
WS_BORDER
| ES_LEFT
| ES_MULTILINE
|
ES_NOHIDESEL
| ES_AUTOHSCROLL
| ES_AUTOVSCROLL
,
0, 0, 0, 0, hwnd, (HMENU) EDITID
, hInst, NULL
) ;
//限制编辑控件最大只能输入32000个字符
SendMessage
(hwndEdit, EM_LIMITTEXT
, 32000, 0L) ;
PopFileInitialize
(hwnd) ; //初始化OPENFILENAME结构
PopFontInitialize
(hwndEdit) ; //创建系统字体副本,运用到编辑控件中
/*调用FindText函数前,必须调用该函数以得到FINDMSGSTRING信息的标识符,
对话框函数在用户点击FindNext按钮或对话框被关闭时利用此标识符传送信息。
FINDMSGSTRING信息的IParam参数包含一个指向FINDREPLACE结构的指针。*/
messageFindReplace = RegisterWindowMessage
(FINDMSGSTRING
) ;
//向父窗口标题栏写入文字
DoCaption
(hwnd, szTitleName) ;
return 0 ;
case WM_SETFOCUS
:
//输入焦点移交到编辑控件上
SetFocus
(hwndEdit) ;
return 0 ;
case WM_SIZE
:
//设置编辑控件大小和位置
MoveWindow
(hwndEdit, 0, 0, LOWORD (lParam), HIWORD (lParam), TRUE
) ;
return 0 ;
case WM_INITMENUPOPUP
: //菜单准备弹出时,设置菜单项是否有效
switch (lParam) //LOWORD (lParam):弹出式菜单索引(从0开始) ;HIWORD (lParam):系统菜单为1,其它为0
{
case 1: // 编辑菜单
//如果编辑控件能够执行Undo动作,那么SendMessage呼叫传回非零值。在这种情况下,选项被启用;否则,选项无效化
EnableMenuItem
((HMENU) wParam, IDM_EDIT_UNDO
, //撤销
SendMessage
(hwndEdit, EM_CANUNDO
, 0, 0L) ? MF_ENABLED
: MF_GRAYED
) ;
//IsClipboardFormatAvailable 判断剪贴板上的数据,如果是CF_TEXT,则该函数返回值为true,否则为false
//剪贴板数据格式:CF_TEXT 以NULL结尾的ASCII字符的文本格式
EnableMenuItem
((HMENU) wParam, IDM_EDIT_PASTE
, //粘贴
IsClipboardFormatAvailable
(CF_TEXT
) ? MF_ENABLED
: MF_GRAYED
) ;
//向编辑控件发送EM_GETSEL消息,将得到目前选中的文字第一位和最后一位的超尾位置
SendMessage
(hwndEdit, EM_GETSEL
, (WPARAM) &iSelBeg,
(LPARAM) &iSelEnd) ;
//如果第一位不等于超尾位置则有效,否则无效
iEnable = iSelBeg != iSelEnd ? MF_ENABLED
: MF_GRAYED
;
EnableMenuItem
((HMENU) wParam, IDM_EDIT_CUT
, iEnable) ;
EnableMenuItem
((HMENU) wParam, IDM_EDIT_COPY
, iEnable) ;
EnableMenuItem
((HMENU) wParam, IDM_EDIT_CLEAR
, iEnable) ;
break ;
case 2: // 搜索菜单
//如果非模态对话框(查找、替换)
未激活
,则有效,否则无效
iEnable = hDlgModeless == NULL
?
MF_ENABLED
: MF_GRAYED
;
EnableMenuItem
((HMENU) wParam, IDM_SEARCH_FIND
, iEnable) ;
EnableMenuItem
((HMENU) wParam, IDM_SEARCH_NEXT
, iEnable) ;
EnableMenuItem
((HMENU) wParam, IDM_SEARCH_REPLACE
, iEnable) ;
break ;
}
return 0 ;
case WM_COMMAND
:
// lParam:子窗口句柄;LOWORD (wParam):子窗口ID
// 判断条件:句柄不为空,消息是由编辑控件发出 。菜单发出的该消息 lParam 参数为0
if (lParam && LOWORD (wParam) == EDITID
)
{
switch (HIWORD (wParam)) // HIWORD (wParam):通知码
{
case EN_UPDATE
: //记录编辑控件的内容已经改变
bNeedSave = TRUE
;
return 0 ;
case EN_ERRSPACE
: //编辑控件执行已经超出空间
case EN_MAXTEXT
: //编辑控件执行时超出最大字符数
MessageBox
(hwnd, TEXT ("Edit control out of space.
"),
szAppName, MB_OK
| MB_ICONSTOP
) ;
return 0 ;
}
break ;
}
switch (LOWORD (wParam)) //菜单ID
{
case IDM_FILE_NEW
: //新建
//如果编辑控件已经改变,或用户在弹出"是否保存"消息框时选择取消,再则保存时出错。那么程序直接返回,无视该消息
if (bNeedSave && IDCANCEL
== AskAboutSave
(hwnd, szTitleName))
return 0 ;
SetWindowText
(hwndEdit, TEXT ("/0
")) ; //设置编辑控件文本内容为空
szFileName[0] = '/0
' ;
szTitleName[0] = '/0
' ;
DoCaption
(hwnd, szTitleName) ; //重写父窗口标题栏文字
bNeedSave = FALSE
; //设置编辑器内容未改变
return 0 ;
case IDM_FILE_OPEN
: //打开
//同 新建 消息的判断处理一样
if (bNeedSave && IDCANCEL
== AskAboutSave
(hwnd, szTitleName))
return 0 ;
//调用自定义函数,激活OPEN通用对话框,如果成功返回非零
if (PopFileOpenDlg
(hwnd, szFileName, szTitleName))
{
/*如果打开文件成功,GetOpenFileName将ofn.lpstrFile成员指向的缓冲区,设置为含有全路径和用户指定的文件名,
ofn.lpstrFile 是一个指向 szFileName 指针的指针,所以szFileName将含有全路径和用户指定的文件名。
PopFileRead 读取打开的文件数据,并显示在编辑控件上。如果成功返回TRUE */
if (!PopFileRead
(hwndEdit, szFileName))
{
//如果读取文件失败,则弹出消息提示框,并将文件路径和文件名置空
OkMessage
(hwnd, TEXT ("Could not read file %s!
"),szTitleName) ;
szFileName[0] = '/0
' ;
szTitleName[0] = '/0
' ;
}
}
DoCaption
(hwnd, szTitleName) ; //设置窗口标题文字 szTitleName 为用户打开的文件名和扩展名
bNeedSave = FALSE
; //标记编辑控件内容为未改变
return 0 ;
case IDM_FILE_SAVE
: //保存
if (szFileName[0]) //如果文件路径存在
{ //调用自定义函数,保存编辑控件中的文本
if (PopFileWrite
(hwndEdit, szFileName))
{
//如果保存成功,设编辑控件内容未改变,返回1
bNeedSave = FALSE
;
return 1 ;
}
else
{
//如果保存失败,弹出消息框,返回0
OkMessage
(hwnd, TEXT ("Could not write file %s
"), szTitleName) ;
return 0 ;
}
}
//连续执行 如果文件路径为空,或者用户选择另存为菜单项
case IDM_FILE_SAVE_AS
: //另存为
//调用自定义函数,激活SAVE通用对话框
if (PopFileSaveDlg
(hwnd, szFileName, szTitleName))
{
//在窗口标题中加入刚命名的文件名和文件扩展名
DoCaption
(hwnd, szTitleName) ;
//调用自定义函数,将编辑控件中的文本,写入到 szFileName 参数中保存的文件路径中
if (PopFileWrite
(hwndEdit, szFileName))
{
//如果保存成功,设编辑控件内容未改变,返回1
bNeedSave = FALSE
;
return 1 ;
}
else
{
//如果保存失败,弹出消息框,返回0
OkMessage
(hwnd, TEXT ("Could not write file %s
"), szTitleName) ;
return 0 ;
}
}
return 0 ;
case IDM_FILE_PRINT
: //打印
//PopPrntPrintFile尚未定义直接返回FALSE,该语句用消息框提示信息
if (!PopPrntPrintFile
(hInst, hwnd, hwndEdit, szTitleName))
OkMessage
(hwnd, TEXT ("Could not print file %s
"), szTitleName) ;
return 0 ;
case IDM_APP_EXIT
: //关闭
SendMessage
(hwnd, WM_CLOSE
, 0, 0) ;
return 0 ;
//发送对应的消息给编辑控件
case IDM_EDIT_UNDO
:
SendMessage
(hwndEdit, WM_UNDO
, 0, 0) ;
return 0 ;
case IDM_EDIT_CUT
:
SendMessage
(hwndEdit, WM_CUT
, 0, 0) ;
return 0 ;
case IDM_EDIT_COPY
:
SendMessage
(hwndEdit, WM_COPY
, 0, 0) ;
return 0 ;
case IDM_EDIT_PASTE
:
SendMessage
(hwndEdit, WM_PASTE
, 0, 0) ;
return 0 ;
case IDM_EDIT_CLEAR
:
SendMessage
(hwndEdit, WM_CLEAR
, 0, 0) ;
return 0 ;
case IDM_EDIT_SELECT_ALL
:
SendMessage
(hwndEdit, EM_SETSEL
, 0, -1) ; //如果LPARAM参数为-1,则表示选择全部
return 0 ;
case IDM_SEARCH_FIND
: //查找
//取得编辑控件中目前选择的起始位置和末尾超尾位置,将超尾位置记录在iOffset中
SendMessage
(hwndEdit, EM_GETSEL
, 0, (LPARAM) &iOffset) ;
//激活Find对话框,如果成功,hDlgModeless 保存对话框窗口句柄
hDlgModeless = PopFindFindDlg
(hwnd) ;
return 0 ;
case IDM_SEARCH_NEXT
: //查找下一个
//取得编辑控件中目前选择的起始位置和末尾超尾位置,将超尾位置记录在iOffset中
SendMessage
(hwndEdit, EM_GETSEL
, 0, (LPARAM) &iOffset) ;
//判断用于查找的字符串是否为空,不为空时返回TRUE
if (PopFindValidFind
())
//调用自定义函数,执行查找处理
PopFindNextText
(hwndEdit, &iOffset) ;
else
//如果用于查找的字符串为空,则激活Find对话框,hDlgModeless 保存对话框窗口句柄
hDlgModeless = PopFindFindDlg
(hwnd) ;
return 0 ;
case IDM_SEARCH_REPLACE
: //替换
SendMessage
(hwndEdit, EM_GETSEL
, 0, (LPARAM) &iOffset) ;
//激活Replace对话框,如果成功,hDlgModeless 保存对话框窗口句柄
hDlgModeless = PopFindReplaceDlg
(hwnd) ;
return 0 ;
case IDM_FORMAT_FONT
: //字体
//调用自定义函数,激活Font对话框。如果用户点击OK,便根据新字体重绘编辑控件内的文本
if (PopFontChooseFont
(hwnd))
PopFontSetFont
(hwndEdit) ;
return 0 ;
case IDM_HELP
: //调用自定义函数弹出HELP提示消息框
OkMessage
(hwnd, TEXT ("Help not yet implemented!
"),
TEXT ("/0
")) ;
return 0 ;
case IDM_APP_ABOUT
: //激活模态对话框 AboutBox ,挂钩到 AboutDlgProc 对话框程序
DialogBox
(hInst, TEXT ("AboutBox
"), hwnd, AboutDlgProc) ;
return 0 ;
}
break ;
case WM_CLOSE
: //关闭
/* 如果 bNeedSave 为FLASE,证明编辑控件中的内容未改变。根据逻辑运算符规则,
当 || 运算符的左边表达式成立时,便不会计算后面的表达式。
否者调用自定义函数,弹出询问消息框,用于保存数据。*/
if (!bNeedSave || IDCANCEL
!= AskAboutSave
(hwnd, szTitleName))
DestroyWindow
(hwnd) ; //向窗口消息处理程序发送一个WM_DESTROY消息
return 0 ;
case WM_QUERYENDSESSION
: //系统关闭时的广播消息
//如果文件不需要保存,或成功保存时,同意系统关机。
if (!bNeedSave || IDCANCEL
!= AskAboutSave
(hwnd, szTitleName))
return 1 ;
return 0 ;
case WM_DESTROY
:
PopFontDeinitialize
() ; //删除之前建立的逻辑字体对象
/* 让系统把WM_QUIT消息放入消息队列中,此消息不会到达窗口消息处理程序,
因为它使GetMessage传回0,并终止消息循环,从而也终止了程序。*/
PostQuitMessage
(0) ;
return 0 ;
default:
//执行查找和替换操作
if (message == messageFindReplace)
{
pfr = (LPFINDREPLACE) lParam ; //取出消息中的FINDREPLACE结构
//FR_DIALOGTERM: 表明对话框已经关闭.
//如果该标记存在,清空保存的窗口句柄
if (pfr->Flags & FR_DIALOGTERM
)
hDlgModeless = NULL
;
//FR_FINDNEXT: 表明用户在查找或替换对话框中点击了"查找下一个"按钮
if (pfr->Flags & FR_FINDNEXT
)
//调用自定义函数,执行查找处理,如果未查找到,弹出消息提示框
if (!PopFindFindText
(hwndEdit, &iOffset, pfr))
OkMessage
(hwnd, TEXT ("Text not found!
"),
TEXT ("/0
")) ;
//FR_REPLACE: 表明用户点击了替换对话框中的"替换"按钮
//FR_REPLACEALL:表明用户点击了替换对话框中的"全部替换替换"按钮
if (pfr->Flags & FR_REPLACE
|| pfr->Flags & FR_REPLACEALL
)
//调用自定义函数,执行一次替换操作。如果失败弹出消息提示框
if (!PopFindReplaceText
(hwndEdit, &iOffset, pfr))
OkMessage
(hwnd, TEXT ("Text not found!
"),
TEXT ("/0
")) ;
//使用循环,执行全部替换操作。
if (pfr->Flags & FR_REPLACEALL
)
while (PopFindReplaceText
(hwndEdit, &iOffset, pfr)) ;
return 0 ;
}
break ;
}
return DefWindowProc
(hwnd, message, wParam, lParam) ;
}
BOOL CALLBACK AboutDlgProc
(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG
:
return TRUE ; //丢弃该消息
case WM_COMMAND
:
switch (LOWORD (wParam))
{
case IDOK:
EndDialog
(hDlg, 0) ; //如果点击OK按钮则结束该对话框
return TRUE
;
}
break ;
}
return FALSE
;
}
/*------------------------------------------
POPFILE.C
-- Popup Editor File Functions
------------------------------------------*/
#include <windows.h>
#include <commdlg.h>
static OPENFILENAME ofn ;
void PopFileInitialize
(HWND hwnd)
{
/*第一个字符串是过滤器描述的显示字符串(例如,“文本文件”),
第二个字符指定过滤样式(例如,“*.TXT”)。
要为一个显示字符串指定多个过滤样式,使用分号(“;”)分隔样式(例如,“*.TXT;*.DOC;*.BAK”)。
一个样式字符串中可以包含有效的文件名字字符及星号(*)通配符。不能在样式字符串中包含空格。*/
static TCHAR szFilter[] = TEXT ("Text Files (*.TXT)/0*.txt/0
") /
TEXT ("ASCII Files (*.ASC)/0*.asc/0
") /
TEXT ("All Files (*.*)/0*.*/0/0
") ;
ofn.lStructSize = sizeof (OPENFILENAME) ; //指定这个结构的大小
ofn.hwndOwner = hwnd ; //指向对话框所有者窗口的句柄
ofn.hInstance = NULL
; //自定义对话框模板资源被载入内存后的句柄
/*指向一对以空字符结束的过滤字符串的一个缓冲。缓冲中的最后一个字符串必须以两个NULL字符结束。*/
ofn.lpstrFilter = szFilter ;
/*指向一个静态缓冲,它包含了一对以空字符结束的过滤器字符串,这个字符串是为了保留用户选择的过滤样式.
在下一次对话框被建立时系统使用这个字符串去初始化用户自定义的文件过滤器*/
ofn.lpstrCustomFilter = NULL
;
/*指明lpstrCustomFilter以TCHARs为单位的缓冲大小。
ANSI版本是字节的个数;Unicode版本是字符的个数。这缓冲应该最小在40个字符长。*/
ofn.nMaxCustFilter = 0 ;
/*指定在文件类型控件中当前选择的过滤器的索引.
缓冲指向被lpstrFilter包含的一对定义了的过滤器的字符串。过滤器的第一对字符串的索引值为1,第二对为2,等等。
0索引指出是通过lpstrCustomFilter指定的定制过滤器.
你可以为对话框指定一个索引作为最初的过滤器描述及过滤器样式。
当用户选择了一个文件时,nFilterIndex返回当前显示的过滤器的索引。
如果nFilterIndex是0及lpstrCustomFilter是NULL,系统使用在lpstrFilter缓冲中的第一个过滤器。
如果所有的三个成员都是0或NULL,系统不使用任何过滤器,在对话框的列表文件中不显示任何文件。*/
ofn.nFilterIndex = 0 ;
/*指向包含初始化文件名编辑控件使用的文件名的缓冲。
如果不需要初始值,这个缓冲的第一个字符必须是NULL。
当GetOpenFileName或GetSaveFileName函数返回成功时,这个缓冲包含驱动器,路径,文件名,及所选择的文件的扩展名。*/
ofn.lpstrFile = NULL
;
/*指定lpstrFile以TCHARs为单位的缓冲大小。ANSI版本是字节的个数;Unicode版本是字符的个数。*/
ofn.nMaxFile = MAX_PATH
;
ofn.lpstrFileTitle = NULL
; //指向接收选择的文件的文件名和扩展名的缓冲(不带路径信息)
ofn.nMaxFileTitle = MAX_PATH
; //指定lpstrFileTitle以TCHARs为单位的缓冲大小。
ofn.lpstrInitialDir = NULL
; //指向以空字符结束的字符串,可以在这个字符串中指定初始目录。
/*指向在对话框的标题栏中放置的字符串。如果这个成员是NULL,系统使用默认标题(另存为或打开)*/
ofn.lpstrTitle = NULL
;
ofn.Flags = 0 ; //位标记的设置,可以使用来初始化对话框。当对话框返回时,它设置的这些标记指出用户的输入。
/*指定从路径开始到通过lpstrFile指定的文件名字符串基于0的偏移,以TCHARs为单位.
例如,如果lpstrFile指向下列的字符串,“c:/dir1/dir2/file.ext”,这个成员包含指出“file.ext”字符串偏移的位置值13.
如果用户选择了多于一个的文件,nFileOffset是到第一个文件名的偏移。*/
ofn.nFileOffset = 0 ;
/*指定从路径开始到通过lpstrFile指定的文件名字符串中扩展名基于0的偏移,以TCHARs为单位.
如果用户没有输入一个扩展名并且lpstrDefExt是NULL,这个成员指定的偏移是结束字符NULL。
如果用户在文件名中输入一个“.”作为最后的字符,这个成员是0。*/
ofn.nFileExtension = 0 ;
/*指向包含默认扩展名的缓冲。如果用户忘记输入扩展名,GetOpenFileName和GetSaveFileName附加这个扩展名到文件名中。
这个字符串可以是任一长度,但只有头三个字符被附加。字符串不包含一个句点(.)*/
ofn.lpstrDefExt = TEXT ("txt
") ;
/*自定义数据,该数据将被lpfnHook成员指出的钩子程序识别.
当系统发送WM_INITDIALOG消息到程序,消息的lParam参数指向当对话框建立时指定的OPENFILENAME结构。*/
ofn.lCustData = 0L ;
ofn.lpfnHook = NULL
; //指向一个钩子程序。除非Flags成员中包含OFN_ENABLEHOOK标记,否则该成员被忽略
/*指向一个以空字符结束的字符串,字符串是对话框模板资源的名字,资源保存在能被hInstance成员识别的模块中 */
ofn.lpTemplateName = NULL
;
}
BOOL PopFileOpenDlg
(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName)
{
ofn.hwndOwner = hwnd ;
//注意:参数 pstrFileName 是一个指针 ,ofn.lpstrFile 也是一个指针。
//这里的赋值操作,表明了ofn.lpstrFile 是一个指向 pstrFileName 指针的指针。
ofn.lpstrFile = pstrFileName ;
//ofn.lpstrFileTitle 是一个指向 pstrTitleName 指针的指针。
ofn.lpstrFileTitle = pstrTitleName ;
//OFN_HIDEREADONLY:隐藏只读复选框
//OFN_CREATEPROMPT:如果用户指定了一个不存在的文件,这个标记使用对话框能提示用户是否新建这个文件
ofn.Flags = OFN_HIDEREADONLY
| OFN_CREATEPROMPT
;
/* 该函数创建一个Open通用对话框.
如果用户指定了一个文件名,点击OK按钮,返回值为非零.
成功时OPENFILENAME结构的IPstrFile成员指向的缓冲区含有全路径和用户指定的文件名.
如果用户取消或关闭Open对话框或错误出现,返回值为零. */
return GetOpenFileName
(&ofn) ;
}
BOOL PopFileSaveDlg
(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName)
{
ofn.hwndOwner = hwnd ;
ofn.lpstrFile = pstrFileName ;
ofn.lpstrFileTitle = pstrTitleName ;
//如果选择的文件已经存在,则产生一个消息框。用户必须确认是否复盖这个文件。
ofn.Flags = OFN_OVERWRITEPROMPT
;
//该函数创建一个Save通用对话框,返回消息和 GetOpenFileName 类似
return GetSaveFileName
(&ofn) ;
}
BOOL PopFileRead
(HWND hwndEdit, PTSTR pstrFileName)
{
BYTE bySwap ;
DWORD dwBytesRead ;
HANDLE hFile ;
int i, iFileLength, iUniTest ;
PBYTE pBuffer, pText, pConv ;
//INVALID_HANDLE_VALUE表示出错
if (INVALID_HANDLE_VALUE
==
/* CreateFile(pstrFileName 要打开的文件名,GENERIC_READ 表示允许对设备进行读访问,
FILE_SHARE_READ 允许对文件进行共享读访问,
NULL 指向一个SECURITY_ATTRIBUTES结构的指针-定义了文件的安全特性,
OPEN_EXISTING 表示文件必须已经存在-向设备提出要求,0 不设置文件属性,
NULL 如果不为零-则指定一个文件句柄-新文件将从这个文件中复制扩展属性) */
// hFile 接受打开的文件句柄
(hFile = CreateFile
(pstrFileName, GENERIC_READ
, FILE_SHARE_READ
,
NULL
, OPEN_EXISTING
, 0, NULL
)))
return FALSE
; //如果打开文件失败,则返回 FALSE
/* GetFileSize(hFile 文件的句柄,
NULL 指定一个长整数,用于装载一个64位文件长度的头32位。如这个长度没有超过2^32字节,则该参数可以设为NULL) */
//iFileLength 接受文件的大小,单位为字节
iFileLength = GetFileSize
(hFile, NULL
) ;
//分配文件大小加2个字节的内存空间
pBuffer = malloc
(iFileLength + 2) ;
/* ReadFile(hFile 要读取的文件的句柄, pBuffer 用于保存读入数据的一个缓冲区,
iFileLength 要读入的字节数, &dwBytesRead 指向实际读取字节数的指针,
NULL 如文件打开时指定了FILE_FLAG_OVERLAPPED,那么必须用这个参数引用一个特殊的结构。
该结构定义了一次异步读取操作。否则,应将这个参数设为NULL) */
ReadFile
(hFile, pBuffer, iFileLength, &dwBytesRead, NULL
) ;
// 关闭打开的文件
CloseHandle
(hFile) ;
//在读取的文件数据末尾追加两个‘/0’,用于表明数据结尾
pBuffer[iFileLength] = '/0
' ;
pBuffer[iFileLength + 1] = '/0
' ;
/*初始化要检查项目
IS_TEXT_UNICODE_SIGNATURE:缓冲区文本含有Unicode字节顺序码(BOM)0XFEFF作为他的第一个字符
IS_TEXT_UNICODE_REVERSE_SIGNATURE: 缓冲区文本含有Unicode反向字节顺序码0XFFFE作为他的第一个字符 */
iUniTest = IS_TEXT_UNICODE_SIGNATURE
| IS_TEXT_UNICODE_REVERSE_SIGNATURE
;
/*IsTextUnicode(pBuffer 指明想检查的字符串地址。此数据是一个void指针,因为不确定是ANSI字符还是Unicode字符的数组,
iFileLength 指向要检查的字节数,由于不知道数据中的编码,所以该参数单位是字节计数而不是字符计数,
该参数检查的字节越多(当然不能才过数据本身),就越可能得到更精确的结果,
&iUniTest 之前初始化的一个整数的地址。对此整数进行初始化,指明你想让函数执行哪种检查。
也可以向此参数传递NULL,这种情况下函数会执行所有能做的检查)
如果函数认为数据包含的是Unicode文本,返回TRUE;否则,返回FALSE。
如果由参数&iUniTest所指向的整数来指定检查方式,函数会在每种检查之后将结果设置到此整数对应的位,然后再返回。 */
if (IsTextUnicode
(pBuffer, iFileLength, &iUniTest))
{ //如果是Unicode文本
// pText指向数据开始的第二个字符处,跳过文本的字符编码标记
pText = pBuffer + 2 ;
iFileLength -= 2 ;
//按位与操作,判断 IS_TEXT_UNICODE_REVERSE_SIGNATURE 检查项是否成立
if (iUniTest & IS_TEXT_UNICODE_REVERSE_SIGNATURE
)
{ //如果反向编码检测成立,则循环反转为顺序编码
for (i = 0 ; i < iFileLength / 2 ; i++)
{
bySwap = ((BYTE *) pText) [2 * i] ;
((BYTE *) pText) [2 * i] = ((BYTE *) pText) [2 * i + 1] ;
((BYTE *) pText) [2 * i + 1] = bySwap ;
}
}
//分配新内存空间,大小为原来的数据大小,之前有 iFileLength -= 2 ;用于下面转换字符串编码
pConv = malloc (iFileLength + 2) ;
#ifndef UNICODE
//如果 UNICODE 没有被宏定义过,则执行(把宽字符串转化成它等价的多字节字符串)
/* WideCharToMultiByte(CP_ACP 指定执行转换的代码页(CP_ACP:ANSI代码页),
0 (第二个参数)允许指定附加控制,它影响字符的区分标记,如重音符号。通常不使用该标记,而把0传给它,
(PWSTR) pText 指向将被转换的unicode字符串,
-1 指定 (PWSTR) pText 参数指向的缓冲区的字符个数。
如果这个值为-1,字符串将被设定为以NULL为结束符的字符串,并且自动计算长度,
pConv 指向接收被转换字符串的缓冲区,
iFileLength + 2 指定 pConv 参数指向的缓冲区最大值(字节)。
若此值为零,函数返回pConv参数指向的目标缓冲区所必需的字节数,
在这种情况下,pConv参数通常为NULL,
最后两个参数lpDefaultChar和pfUsedDefaultChar:
如果宽字节字符不能被转换