相关函数说明:
SendMessage
函数功能:该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。而函数PostMessage不同,将一个消息寄送到一个线程的消息队列后立即返回。
函数原型:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);
参数:
hWnd:其窗口程序将接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。
Msg:指定被发送的消息。
wParam:指定附加的消息指定信息。
IParam:指定附加的消息指定信息。
返回值:返回值指定消息处理的结果,依赖于所发送的消息。
备注:需要用HWND_BROADCAST通信的应用程序应当使用函数RegisterWindowMessage来为应用程序间的通信取得一个唯一的消息。
如果指定的窗口是由调用线程创建的,则窗口程序立即作为子程序调用。如果指定的窗口是由不同线程创建的,则系统切换到该线程并调用恰当的窗口程序。线程间的消息只有在线程执行消息检索代码时才被处理。发送线程被阻塞直到接收线程处理完消息为止。
#include <windows.h>
#include <string.h>
#include "menutest.h"
#define FILE_LIST DDL_DIRECTORY|DDL_READWRITE
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam); //窗口函数声明
BOOL ShowFileInfo(HWND hWnd,HDC hDC,HDROP hDropInfo);
BOOL CALLBACK DlgProcGetFileName(HWND,UINT,WPARAM,LPARAM); //获取文件名
BOOL FileToEditBox(HWND,LPSTR); //文件到编辑框
BOOL EditBoxToFile(HWND,LPCTSTR); //编辑框到文件
BOOL EditBoxToClip1(HWND); //编辑框到剪贴板(复制)
BOOL EditBoxToClip2(HWND); //编辑框到剪贴板(剪切)
BOOL ClipToEditBox(HWND); //剪贴板到编辑框
bool check(char* , char* ); //判断两个字符串是否相等
HWND hWnd; //窗口句柄
HINSTANCE hInst; //应用程序实例句柄
HWND hList; //文件列表框句柄
HANDLE hFile; //文件句柄
HWND hWndEdit; //编辑框句柄
HWND hStatic; //状态栏句柄
OPENFILENAME ofn;
char szFile[255];
char szFileTitle[255];
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
WNDCLASSEX wndclass;
MSG msg;
HACCEL hAccel; // 定义加速键句柄
// 为窗口类结构赋值
wndclass.cbSize = sizeof (wndclass);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance,"MYICON"); //设置程序的图标(不能缺少)
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = CreateSolidBrush(RGB(192,192,192));
wndclass.lpszMenuName = "Menu";
wndclass.lpszClassName = "TestWindowClass";
wndclass.hIconSm = LoadIcon(hInstance,"MYICON"); //设置程序的图标(不可缺少)
// 注册窗口类
if (!RegisterClassEx(&wndclass)) return 0;
// 用上面创建的类(即已经赋值的类)创建新窗口
hWnd = CreateWindowEx( //创建一个窗口并赋予窗口句柄hWnd
0, //扩展窗口风格,为默认
"TestWindowClass", //创建窗口所用的类(这是上面的类的名字)
//不同的类以名字来区分!!!
"记事本仿真程序^O^", //窗口的名称,(在标题栏)
WS_OVERLAPPEDWINDOW, //窗口风格为OVERLAPPED风格(和记事本一样的),
CW_USEDEFAULT, //这四个参数定义了窗口的位置和大小,现为默认
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, //父窗口句柄,这里没有,所以设为NULL
NULL, //菜单句柄,,,这里没有,,,为NULL
hInstance, //创建窗口的应用程序的当前句柄
NULL); //创建参数,用于给程序传递数据,程序没用到,,所以为空
if (!hWnd) return FALSE; //如果创建窗口失败,返回FALSE
hInst=hInstance;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
SendMessage(hWnd,WM_COMMAND,IDM_NEW,0L);
//加载加速键
hAccel=LoadAccelerators(hInstance,MAKEINTRESOURCE(IDR_ACCELERATOR1)); //加载快捷键表,若你在程序中没有快捷键表,则不需要用这个函数。
while (GetMessage(&msg,NULL,0,0))
{
//在消息循环中截获加速键消息
if(!TranslateAccelerator(hWnd,hAccel,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0; // 如果没有特殊要求,这里也可以是代表成功执行
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
HDC hDC;
RECT ClientRect;
LPCTSTR lpTemp=""; // 空字符串
char *p=NULL;
static bool flag=false; //若没有打开文件,flag=flase
static bool flag2=false; //若没有新建文件,flag2=false
static bool flag3=false; //用来判断文件名是否带了后缀,在IDM_SAVE 中将会用到
static bool flag4=false; //用来判断是否保存了文件
switch (message)
{
case WM_CREATE:
GetClientRect(hwnd,&ClientRect); //获取客户区大小
hWndEdit=CreateWindow("EDIT", //创建编辑框
NULL,
WS_CHILD|WS_VISIBLE|WS_VSCROLL|ES_MULTILINE|WS_BORDER,
ClientRect.left,
ClientRect.top,
ClientRect.right,
ClientRect.bottom,
hwnd,
(HMENU)ID_EDITCHILD,
hInst,
NULL);
EnableWindow(hWndEdit,0); //使编辑框不能接受输入
DragAcceptFiles( hwnd,TRUE ); //API函数:允许hWnd所指的窗口实现文件拖放
// 如果没有这个函数或设置为FALSE
// 窗口都不能实现文件的拖放
return 0;
case WM_SIZE: //当窗口大小改变的时候,编辑框与状态栏跟着改变
MoveWindow(hWndEdit,0,0,LOWORD(lParam),HIWORD(lParam),true); //编辑框
return 0;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDM_OPEN:
SendMessage(hWndEdit,EM_SETSEL,0,-1); //选中所有文本
SendMessage(hWndEdit,EM_REPLACESEL,wParam,(DWORD)lpTemp); //用空串代码
EnableWindow(hWndEdit,0); //使编辑框不能接受输入
ZeroMemory(&ofn,sizeof(OPENFILENAME));
ofn.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER | OFN_FILEMUSTEXIST |OFN_PATHMUSTEXIST ;
ofn.lpstrFile=szFile;
ofn.nMaxFile=sizeof(szFile);
ofn.lpstrFileTitle=szFileTitle;
ofn.lpstrInitialDir=NULL;
ofn.nMaxFileTitle = NULL;
ofn.lpstrFilter="文本文件\0*.txt";
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner=hwnd; //父窗口句柄
//注:如果不指明父窗口句柄,当我们打开通用对话框
// 时将仍然可以对主窗口进行操作,这不是我们需要的
// 只有指明了父窗口句柄才能把焦点限定在通用对话框
if (GetOpenFileName(&ofn)==TRUE)
{
EnableWindow(hWndEdit,1); //使编辑框可以接受输入
FileToEditBox(hwnd,szFile); //文件到编辑框!!!!!!!!!!!!
}
EnableWindow(hWndEdit,1); //使编辑框可以接受输入
flag=true; //打开了一个文件,flag=true
flag4=false; //打开了一个文件,还未保存,flag4=false
return 0;
case IDM_NEW:
//弹出文件名对话框
SendMessage(hWndEdit,EM_SETSEL,0,-1); //选中所有文本
SendMessage(hWndEdit,EM_REPLACESEL,wParam,(DWORD)lpTemp); //用空串代码
EnableWindow(hWndEdit,1); //允许编辑框输入
SetFocus(hWndEdit); //编辑框获得焦点
flag2=true; //新建了文件,flag2=true
flag4=false; //新建了文件,还未保存,flag4=false
return 0;
case IDM_CLOSE:
SendMessage(hWndEdit,EM_SETSEL,0,-1); //选中所有文本
SendMessage(hWndEdit,EM_REPLACESEL,wParam,(DWORD)lpTemp); //用空串代码
EnableWindow(hWndEdit,0); //禁止编辑框输入
flag=false;
flag2=false;
return 0;
case IDM_SAVE:
//将编辑框中所有内容输出到文件
if(flag==true || flag2==true)
{
if(flag4==false)
{
ofn.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER |OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT;
ofn.lpstrFile=szFile;
ofn.nMaxFile=sizeof(szFile);
ofn.lpstrFileTitle=szFileTitle;
ofn.lpstrInitialDir=NULL;
ofn.nMaxFileTitle = NULL;
ofn.lpstrFilter="文本文件\0*.txt";
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.lpstrTitle ="另存为...";
ofn.hwndOwner=hwnd; //父窗口句柄
EnableWindow(hWndEdit,0); //使编辑框不能接受输入
GetSaveFileName(&ofn);
EnableWindow(hWndEdit,1); //使编辑框可以接受输入
p=szFileTitle;
while(*p!='\0')
{
if(*p=='.') //字符串里有"."号,说明文件名带了后缀
{
flag3=true; //文件名带了后缀, flag3=true
if(check(p,".txt") || check(p,".TXT")) //如果后缀是".txt" 或".TXT"
break; //OK,跳出循环
else //如果后缀不是".txt" 或".TXT"
strcat(p,".txt"); //在其末尾加上".txt"
}
p++;
}
if(flag3==false)
{
strcat(p,".txt"); //文件名没有带后缀,我们给它加上后缀
}
}
EditBoxToFile(hwnd,szFileTitle);
flag4=true;
}
return 0;
case IDM_SAVEAS:
if(flag==true || flag2==true)
{
ofn.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER |OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT;
ofn.lpstrFile=szFile;
ofn.nMaxFile=sizeof(szFile);
ofn.lpstrFileTitle=szFileTitle;
ofn.lpstrInitialDir=NULL;
ofn.nMaxFileTitle = NULL;
ofn.lpstrFilter="文本文件\0*.txt";
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.lpstrTitle ="另存为...";
ofn.hwndOwner=hwnd; //父窗口句柄
EnableWindow(hWndEdit,0); //使编辑框不能接受输入
GetSaveFileName(&ofn);
EnableWindow(hWndEdit,1); //使编辑框可以接受输入
p=szFileTitle;
while(*p!='\0')
{
if(*p=='.') //字符串里有"."号,说明文件名带了后缀
{
flag=true; //设置flag=false;
if(check(p,".txt") || check(p,".TXT")) //如果后缀是".txt" 或".TXT"
break; //OK,返回
else //如果后缀不是".txt" 或".TXT"
strcat(p,".txt"); //在其末尾加上".txt"
}
else //若字符串里没有"."号,说明文件名没有带后缀
flag=false; //设置flag=false;
p++;
}
if(flag==false) //若flag=false,说明文件名没有带后缀
{
strcat(szFileTitle,".txt"); //给文件名加上后缀".txt"
flag=true;
}
if(flag==true)
{
EditBoxToFile(hwnd,szFileTitle);
flag4=true;
}
}
return 0;
case IDM_EXIT:
SendMessage(hwnd,WM_DESTROY,0,0);
return 0;
case IDM_COPY:
EditBoxToClip1(hwnd);
return 0;
case IDM_CUT:
EditBoxToClip2(hwnd);
return 0;
case IDM_PASTE:
ClipToEditBox(hwnd);
return 0;
case IDM_ABOUT:
MessageBox(hwnd,TEXT("记事本仿真程序(V1.0)\n\n广西工学院计:黄伟林\nQQ: 362176730\n最后更新: 2005-1-19"),TEXT("记事本仿真程序(V1.0)"),MB_OK|MB_ICONINFORMATION);
return 0;
}
return 0;
case WM_DROPFILES: //当有文件被拖入窗口并放下时激发此消息
HDROP hDropInfo; //HDROP句柄,用以存放拖入文件的信息
hDropInfo = ( HDROP )wParam; //初始化hDropInfo(不进行初始化运行会出错)
hDC = GetDC( hwnd );
ShowFileInfo( hwnd,hDC,hDropInfo );
DragFinish( hDropInfo );
ReleaseDC( hwnd,hDC );
flag=true; //打开了一个文件,flag=true
flag4=false; //打开了一个文件,还未保存,flag4=false
return 0;
case WM_KEYDOWN:
switch(wParam)
{
case VK_ESCAPE:
DestroyWindow(hList); //消毁文件列表框
return 0;
}
return 0;
case WM_CLOSE: // 窗口关闭前的消息(比如用户点了关闭按钮)
DWORD dwFileSize;
dwFileSize=SendMessage(hWndEdit,WM_GETTEXTLENGTH,0,0);
if((flag==true||flag2==true)&&flag4==false) //如果新建了文件或打开了文件
{ //并且文件没有被保存过
if(dwFileSize!=0) //如果编辑框内容不为空
{
int t;
t=::MessageBox(NULL,"文件还未保存,是否要保存?","提示",MB_YESNOCANCEL|MB_ICONINFORMATION);
if(t==IDYES)
{
SendMessage(hWnd,WM_COMMAND,IDM_SAVEAS,0L); //保存文件
DestroyWindow(hwnd); //毁灭窗口
return 0;
}
else if(t==IDCANCEL)
{
return 0;
}
}
}
DestroyWindow(hwnd);
return 0; // 此时Windows还根本没有对窗口做任何事,可以用MessageBox来测试
case WM_DESTROY: // 窗口关闭以后的消息,此时Windows已经毁坏了窗口
DragAcceptFiles( hwnd,FALSE );
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam); // 默认消息处理
}
BOOL FileToEditBox(HWND hwnd, LPSTR lpszFileName)
{
DWORD dwFileSize,dwByteRead; //文件大小,文件读入字节
char *lpBufPtr=NULL; //文件缓冲区
//打开文件
hFile=CreateFile(lpszFileName, //文件名
GENERIC_READ, //只进行读文件操作
FILE_SHARE_READ, //读方式:共享读
NULL,
OPEN_EXISTING, //打开一个文件,如果文件不存在,函数失败
FILE_ATTRIBUTE_NORMAL, //常规文件
(HANDLE)NULL);
if(hFile!=INVALID_HANDLE_VALUE) //若打开文件成功
{
dwFileSize=GetFileSize(hFile,NULL); //读取文件大小
if(dwFileSize!=0xFFFFFFFF) //若读取文件大小成功
{
lpBufPtr=(char*)malloc(dwFileSize); //开辟文件缓冲区
if(lpBufPtr!=NULL) //若开辟文件缓冲区成功
{
//读取文件
ReadFile(hFile, //文件句柄
(LPVOID)lpBufPtr, //文件缓冲区指针
dwFileSize, //文件大小
&dwByteRead, //记录读入了多少字节
NULL); //从文件当前位置读取
if(dwByteRead!=0) //若读取文件成功
{
//将文件写入编辑框
SendMessage(hWndEdit,WM_SETTEXT,0,(LPARAM)lpBufPtr);
}
else
{
MessageBox(NULL,"读入字节数为0 ","",0);
free(lpBufPtr);
return 0;
}
}
else
{
MessageBox(hwnd,"内存分配失败","",0);
return 0;
}
}
else
{
MessageBox(hwnd,"获取文件大小失败","",0);
return 0;
}
}
else
{
MessageBox(hwnd,"打开文件失败","",0);
return 0;
}
CloseHandle(hFile);
return 1;
}
BOOL EditBoxToFile(HWND hwnd,LPCTSTR lpszFileName)
{
DWORD dwFileSize,dwByteWrite; //文件大小,已写入的字节数
char *lpBufPtr=NULL; //文件缓冲区
hFile=CreateFile(lpszFileName,
GENERIC_READ|GENERIC_WRITE, //读写文件
FILE_SHARE_WRITE, //写方式:共享写
NULL,
CREATE_ALWAYS, //创建一个文件,如果文件已存在将被重写
FILE_ATTRIBUTE_NORMAL, //常规文件
(HANDLE)NULL);
if(hFile!=INVALID_HANDLE_VALUE)
{
//读取编辑框中的文本的大小
dwFileSize=SendMessage(hWndEdit,WM_GETTEXTLENGTH,0,0);
dwFileSize+=1; //文本长度+,否则丢失最后一个字符
if(dwFileSize!=0) //若读取文件大小成功
{
lpBufPtr=(char*)malloc(dwFileSize); //开辟文件缓冲区
if(lpBufPtr!=NULL) //若开辟文件缓冲区成功
{
//读取编辑框中的内容
GetWindowText(hWndEdit,lpBufPtr,dwFileSize);
//将文件缓冲区内容写入文件
WriteFile(hFile,(LPVOID)lpBufPtr,dwFileSize,&dwByteWrite,NULL);
free(lpBufPtr); //释放缓冲区
}
else
{
// MessageBox(NULL,"内存分配失败","",0);
return 0;
}
}
else
{
// MessageBox(NULL,"编辑框内容为空","",0);
CloseHandle(hFile);
return 0;
}
}
else
{
// MessageBox(NULL,"创建文件失败","",0);
return 0;
}
CloseHandle(hFile);
return 1;
}
//编辑框到剪贴板(复制操作)
BOOL EditBoxToClip1(HWND hWnd)
{
LPTSTR lpCopyStr,lpText;
HANDLE hText; //全局内存句柄
DWORD dPos;
WORD wStart,wEnd;
char *lpBufPtr;
DWORD dwFileSize; //文本大小
//得到选中的文本位置
dPos=SendMessage(hWndEdit,EM_GETSEL,NULL,NULL);
wEnd=HIWORD(dPos); //开始位置
wStart=LOWORD(dPos); //结束位置
//获得文本框中文本长度
dwFileSize=SendMessage(hWndEdit,WM_GETTEXTLENGTH,0,0L);
lpBufPtr=(char*)malloc(dwFileSize+2); //开辟文本缓冲区
if(lpBufPtr!=NULL)
{
// 读取编辑框文本内容保存到lpBufPtr(读取的是所有文本,而不仅仅是选中的文本)
SendMessage(hWndEdit,WM_GETTEXT,dwFileSize,(LPARAM)lpBufPtr);
// 截取我们选中的文本
lpCopyStr=lpBufPtr+wStart;
*(lpCopyStr+(wEnd-wStart))='\0';
}
else
{
MessageBox(hWnd,"内存分配失败","",MB_OK|MB_ICONEXCLAMATION);
return 0;
}
if(!(hText=GlobalAlloc(GHND,wEnd-wStart+1)))
{
MessageBox(hWnd,"全局内存分配失败","",MB_OK);
return 0;
}
//复制文本到全局内存
lpText=(LPTSTR)GlobalLock(hText); //锁定全局内存并返回全局内存指针
lstrcpy(lpText,lpCopyStr); //复制文本到全局内存
GlobalUnlock(hText); //解锁全局内存
//以下为剪贴板操作
if(!OpenClipboard(hWnd)) //打开剪贴板
{
MessageBox(hWnd,"剪贴板打开失败!","",MB_OK);
return 0;
}
EmptyClipboard(); //清空剪贴板
SetClipboardData(CF_TEXT,hText); //设置剪贴板内容
CloseClipboard(); //关闭剪贴板
hText=NULL;
return 1;
}
//编辑框到剪贴板(剪切操作)
BOOL EditBoxToClip2(HWND hWnd)
{
EditBoxToClip1(hWnd);
SendMessage(hWndEdit,EM_REPLACESEL,1,(LPARAM)""); //以空格取代编辑框被选中的文本
return 1;
}
//剪贴板到编辑框
BOOL ClipToEditBox(HWND hWnd)
{
LPTSTR lpPasteStr,lpText;
HANDLE hText;
DWORD dPos;
WORD wStart,wEnd;
//得到文本位置
dPos=SendMessage(hWndEdit,EM_GETSEL,NULL,NULL);
wEnd=HIWORD(dPos);
wStart=LOWORD(dPos);
if((wEnd-wStart)>=0) //文本长度必须>=0
{
if(!(IsClipboardFormatAvailable(CF_TEXT)))
{
/*---------API函数小帖士-------------
名称 IsClipboardFormatAvailable
原型 BOOL IsClipboardFormatAvailable (UINT uFormat)
描述 检测剪贴板是否支持某种数据类型
返回值:成功返回TRUE,失败返回FALSE
现支持类型: CF_TEXT,即目前只支持检测文本模式
------------------------------*/
MessageBox(hWnd,"剪贴板文本模式不可用","",MB_OK);
return 0;
}
if(!OpenClipboard(hWnd))
{
MessageBox(hWnd,"剪贴板打开失败","",MB_OK);
return 0;
}
if(!(hText=GetClipboardData(CF_TEXT)))
{
MessageBox(hWnd,"无法读取剪贴板数据","",MB_OK);
return 0;
}
lpText=(LPTSTR)GlobalLock(hText); //锁定内存并返回内存指针
lpPasteStr=(LPTSTR)malloc(GlobalSize(hText)); //根据剪贴板内容开辟文本缓冲区
lstrcpy(lpPasteStr,lpText); //文本复制
GlobalUnlock(hText); //解锁全局内存
//在编辑框中的光标位置插入lpPasteStr
SendMessage(hWndEdit,EM_REPLACESEL,1,(LPARAM)lpPasteStr);
}
else
MessageBox(hWnd,"文本插入位置错误","",MB_OK);
return 1;
}
bool check(char* a, char* b) //判断两个字符串是否相等
{
int i;
int j=strlen(b);
for(i=0; i<j; i++)
{
if(*a==*b)
{
a++;
b++;
}
else
return 0;
}
return 1;
}
BOOL ShowFileInfo( HWND hwnd,HDC hDC,HDROP hDropInfo )
{
WORD cFiles;
char lpszFile[255];
/*----------API 函数小帖士----------------
API函数DragQueryFile():
UINT DragQueryFile(HDROP hDrop,
UINT iFile,
LPTSTR lpszFile,
UINT cch )
---- 其中hDrop是指向拖动文件结构的句柄;
---- iFile 是以开始的被托动文件的序号,因为一次可能拖动多个文件。当此参数
---- 设为xFFFFFFFF,则函数返回拖动文件的数量;
---- lpszFile 是指向文件名的缓冲区;
---- cch 是文件名缓冲区的大小,即文件名的字符数。
----------------------------------*/
// 返回拖入的文件数目
cFiles = DragQueryFile( hDropInfo,( UINT )0xFFFFFFFF,( LPTSTR )NULL,( UINT )NULL );
if( cFiles > 1 ) //如果施入的文件不只一个,显示如下信息:
{
// MessageBox(NULL,"你拖入的文件过多,请重新操作","提示",0);
return FALSE;
}
else //如果拖入的文件只有一个
{
DragQueryFile( hDropInfo,0,lpszFile,sizeof( lpszFile ) );
//从hDropInfo 获取文件信息存放到lpszFile
//注:DragQueryFile()函数取得的信息是完整的文件名,
// 即除了文件名外还包含了文件路径,可以用MessageBox()函数测试
EnableWindow(hWndEdit,1); //使编辑框可以接受输入
FileToEditBox(hwnd,lpszFile); //文件到编辑框!!!!!!!!!!!!
}
return TRUE;
}