|
|
2008年2月28日
这是一个小的例子在于演示SendMessage和PostMessage的区别,其区别简单来说,就是前者会等待对方的窗口过程返回,后者则仅仅给对方的消息队列中投放一个消息立即返回,不会阻塞。因此两个函数的返回值不同,前者为窗口过程的返回值(LRESULT),后者仅投递消息,因此仅返回BOOL表示是否投递成功。

源代码下载链接(VC6):
http://www.cnblogs.com/Files/hoodlum1980/SendMsgTest.rar
【声明】严格来讲,这篇文章不属于我的原创。我在这里参考了codeproject上的国外作者的模仿MSN浮出窗口的C#代码。换句话说,可以认为我把C#代码翻译成了C++代码。另外,为了简化代码,CloseButton我没有采用自己绘制,而是用一个ImageButton来代替。
效果如图所示:
窗口浮出时,停靠于屏幕右下角的位置,这里我借用了博客园的图标(仅用作范例),该窗口主要由用户自定义绘制完成。同时,为了防止浮出窗口夺取焦点, SWP_NOACTIVATE标识似乎有时候并没有很好的符合预期,因此我在重设窗口位置的前后强行设置了前台窗口。
该示例的源代码(VC6.0 + Windows Platform SDK)下载:
http://www.cnblogs.com/Files/hoodlum1980/JRL.NotifyWndDemo.rar
有的选项可能仅提供C++和Windows Platform SDK中的方法(API):
(1)将窗口设为顶层窗口:
c++:
//[注意]:BringWindowToTop( hwnd )不会使窗口成为TopMost窗口!
SetWindowPos(hDlg,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE); //忽略x,y,cx,cy参数
c#:
form1.TopMost=true;
(2)设置窗口透明度:
//将窗口设置为图层窗口样式
SetWindowLong(hDlg,GWL_EXSTYLE, GetWindowLong(hDlg, GWL_EXSTYLE) | WS_EX_LAYERED);
//设置alpha值,从0~255
BYTE alpha=200;
SetLayeredWindowAttributes(hDlg,0, alpha, LWA_ALPHA);
(3)已知一个窗口句柄,获取窗口所在程序的HINSTANCE:
HINSTANCE hInstance = (HINSTANCE)GetWindowLong(m_hParentWnd, GWL_HINSTANCE);
(4)获取光标位置:
BOOL GetCursorPos(LPPOINT lpPoint);
(5)使对话框中的某个TextBox(或其他控件)具有输入焦点:
HWND SetFocus(HWND hWnd);
如果该方法不能工作,则可以模拟发送一个鼠标点击的消息给该控件:
PostMessage(hWnd, WM_LBUTTONDOWN, 0, 0);//表示于客户区坐标(0,0)处单击
PostMessage(hWnd, WM_LBUTTONUP, 0, 0);
(6)使对话框定时关闭:
在对话框窗口过程中,在对话框初始化消息分支中安装和设定一个定时器,在WM_TIMER消息分支中调用EndDialog。
(7)使一个菜单灰化或者重新使能:
设置:BOOL EnableMenuItem(HMENU hMenu, UINT uIDEnableItem, UINT uEnable);
查询:UINT GetMenuState(HMENU hMenu, UINT uId, UINT uFlags);
(8)获取对话框中的CheckBox是否被选中,设置CheckBox的状态:
查询:if ( IsDlgButtonChecked(hDlg, nIDButton) == BST_CHECKED) ...
设置:BOOL CheckDlgButton(HWND hDlg, int nIDButton, UINT uCheck);
(9)获取对话框中的文本输入框填写的数字:
UINT GetDlgItemInt(
HWND hDlg,
int nIDDlgItem,
BOOL * lpTranslated, //告知调用方是否转换成功
BOOL bSigned //是否需要考虑负号。
);
获取对话框控件的文本:
UINT GetDlgItemText(
HWND hDlg,
int nIDDlgItem,
LPTSTR lpString,
int nMaxCount
);
(10)如何处理对话框中的TreeView控件的选择节点变化,节点展开,节点折叠等事件:
对话框中的控件上发生事件时,通常会给它们的父窗口发送WM_NOTIFY消息。
LRESULT OnNotify(WORD uMsg, WORD wParam, LONG lParam, BOOL& bHandled)
{
LPNMHDR hdr=(LPNMHDR)lParam;
/*
code
Notification code. This member can be a control-specific notification code or it
can be one of the common notification codes.
*/
if(hdr->code==TVN_SELCHANGED)
{
//树节点发生改变
}
else if(hdr->code==TVN_ITEMEXPANDED)
{
LPNMTREEVIEW pnmtv = (LPNMTREEVIEW) lParam;
/*
#define TVE_COLLAPSE 0x0001
#define TVE_EXPAND 0x0002
#define TVE_TOGGLE 0x0003
*/
}
return 0;
}
(11)如果计算SYSTEMTIME加上一段时间后的SYSTEMTIME:
 Code_AddSeconds
typedef union
{
FILETIME fileTime; //文件时间
ULONGLONG uint64; //64-bit unsigned integer.
} UNION_FILETIME;
//为一个系统时间增加指定的秒数
BOOL AddSeconds(CONST SYSTEMTIME *lpSrcTime, SYSTEMTIME *lpDestTime, int seconds)
{
UNION_FILETIME uFileTime;
if(! SystemTimeToFileTime(lpSrcTime, (LPFILETIME)&uFileTime))
return FALSE;
//在文件时间上加上指定的分钟(转化为。。) 文件时间的单位0.0000001 sec, (10^(-7) sec)
//判断分钟的符号
if(seconds>0)
uFileTime.uint64 += UInt32x32To64(seconds,10000000);
else
uFileTime.uint64 -= UInt32x32To64(-seconds,10000000);
return FileTimeToSystemTime((FILETIME*)&uFileTime, lpDestTime);
}
(12)获取用户最近一次鼠标键盘输入到现在的时间(用户离开电脑的时间):
LASTINPUTINFO lastInput;
lastInput.cbSize = sizeof(lastInput); //important,donot forget!
GetLastInputInfo(&lastInput);
DWORD dwTicksSinceLastInput = GetTickCount() - lastInput.dwTime; (单位:毫秒)
备注:GetTickCount:获取自开机到现在的毫秒数。
(13)防止一个程序运行多个进程实例:通过创建mutex对象来判断当前是否已经有进程在运行;
 Code_Mutex
//打开mutex,参数:request full access,handle not inheritable,object name
hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, WINLOCK_MUTEX_NAME);
if(hMutex == NULL)
{
//说明系统中尚无本进程,进程退出后系统自动销毁该对象
//创建mutex,参数:no security descriptor,mutex not owned,object name
hMutex = CreateMutex(NULL, FALSE, WINLOCK_MUTEX_NAME);
}
else
{
//退出
exit(0);
}
(14)控制窗口是否在任务栏显示一个按钮:
a. 通过设定对话框的样式实现:
显示:创建一个没有OWNER的窗口,并设置WS_EX_APPWINDOW 扩展样式;
不显示:创建一个没有OWNER的窗口,并设置WS_EX_TOOLWINDOW 扩展样式;
b. 通过任务栏的COM对象来实现:
 Code_TaskbarList
HRESULT result;
ITaskbarList* pTaskbarList;
result = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER,
IID_ITaskbarList, (void**)&pTaskbarList);
pTaskbarList->HrInit();
if(bShowInTaskbar) //在任务栏显示按钮
{
pTaskbarList->AddTab(hWnd);
}
else //在任务栏隐藏按钮
{
pTaskbarList->DeleteTab(hWnd);
}
pTaskbarList->Release();
(15)如何在通知栏(System Notify Area)放置一个图标(NotifyIcon):
 Code_Shell_NotifyIcon
NOTIFYICONDATA m_NotifyData;
HICON hicon = LoadIcon(hInstance,MAKEINTSOURCE(IDI_TRAYICONID));
m_NotifyData.cbSize = sizeof(NOTIFYICONDATA );//字节大小
m_NotifyData.hIcon = hicon;//图标句柄
m_NotifyData.hWnd = hwnd;//窗口句柄
m_NotifyData.uID = 0;//图标ID
#define WM_TRAYICON (WM_USER+120)
m_NotifyData.uCallbackMessage = WM_TRAYICON; //产生的消息
strcpy(m_NotifyData.szTip, "Icon's Tip Text");//鼠标在图标上悬停时的ToolTip Text
m_NotifyData.uFlags = NIF_MESSAGE|NIF_TIP|NIF_ICON; //设置要修改哪些属性
Shell_NotifyIcon(NIM_ADD, (PNOTIFYICONDATA)&m_NotifyData);//添加
(16)如何关闭或者注销计算机:
用户进程启动以后通常不具有关机权限,因此要关闭计算机,首先需要调整我们的进程的权限,获取关机权限:
 Code_ExitWindowsEx
//关闭计算机
LRESULT ShutDown()
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
HANDLE hProcess;
int err;
LPVOID lpMsgBuf;
//当前进程的句柄
hProcess=GetCurrentProcess();
//获取调整权限和查询权限的token
if (OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
// open and check the privileges for to perform the actions
// #define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege")
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
if(AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0))
{
//adjust the privilege to perform the action,
//现在我们的进程已经具有了权限!
//关机
ExitWindowsEx(EWX_SHUTDOWN|EWX_POWEROFF|EWX_FORCE,0);
//注销
//ExitWindowsEx(EWX_LOGOFF|EWX_FORCE,0);
//重启
//ExitWindowsEx(EWX_REBOOT|EWX_FORCE,0);
}
else
MessageBox(NULL,"无法关机","HanTing Hotels",MB_OK);
}
err = GetLastError();
if(err)
{
// 将错误代码转换成文本
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, //dwFlags
NULL, //lpSource
err, //dwMessageId
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //dwLanguageId
(LPTSTR)&lpMsgBuf, //lpBuffer
0, //nSize
NULL //Arguments
);
MessageBox(NULL,(LPTSTR)lpMsgBuf, "", MB_OK|MB_ICONERROR);
LocalFree(lpMsgBuf);
}
else
{
//没有错误出现, 结束自身进程
PostQuitMessage(0);
exit(0);
}
return 1;
}
(17)如何在注册表中写入一个键值:
 Code_RegSetValueEx
//--------------------------
// write a keyvalue
//--------------------------
HKEY hKey;
LONG result;
DWORD dwType=REG_SZ;//C字符串
char lpData[128];
DWORD cbData=strlen(value)+1;//设置字符串时,size必须要包含结尾的\0
if (RegOpenKey(HKEY_LOCAL_MACHINE, "keyName", &hKey) != ERROR_SUCCESS)
{
//如果键不存在,则创建它
if (RegCreateKey(HKEY_LOCAL_MACHINE, "keyName", &hKey) != ERROR_SUCCESS)
return FALSE;
}
result = RegSetValueEx(hKey, "valueName", 0, dwType, (VOID*)lpData, cbData);
RegCloseKey(hKey);
//--------------------------
// query a keyvalue
//--------------------------
if (RegOpenKey(HKEY_LOCAL_MACHINE, "keyName", &hKey) != ERROR_SUCCESS)
{
return FALSE;
}
result = RegQueryValueEx(hKey, "valueName", NULL, &dwType, lpData, &cbData);
RegCloseKey(hKey);
(18)如何获取位图的尺寸:
BOOL GetBitmapDimensionEx(
HBITMAP hBitmap, // handle to bitmap
LPSIZE lpDimension // dimensions
);
BalloonTip通常出现在位于屏幕右下角的Tray(成为通知栏,或系统托盘)的Icon上,比如用户插拔USB设备时的气泡提示。该函数位于Shell32中,是通过调用下面这个API函数实现的, BOOL Shell_NotifyIcon( DWORD dwMessage, PNOTIFYICONDATA lpdata ); 该函数用于控制对TrayIcon进行控制,可以弹出BalloonTip。然后却只能局限于Tray位置。而在QQ的聊天对话框中,我们发现如果不输入内容而试图发送消息时,就会在按钮上弹出这样的Tip。为此,我在C#中写了一个类似的窗口,可以在任意位置浮出,效果如下:
这是测试程序的截图。在实现时,略微参考了codeproject上的仿MSN浮出窗口的代码。其涉及的主要麻烦是,为了提供足够灵活的接口,应该如何处理窗口上各个元素布局。为了简单期间,这里仅仅提供了“箭头”位于右下角的布局方式。(很显然该箭头一共可以有8个停靠位置)。
(1)在弹出时,不夺走其他窗口焦点。为此使用了API的ShowWindow函数: ShowWindow(this.Handle, SW_SHOWNOACTIVATE);
(2)窗体上一共包含4项主要内容:图标,标题,内容文本,关闭按钮。用户可以配置他们,例如选择图标(可以由外部设置或者使用内置图标),是否显示关闭按钮,是否自动关闭(如果把TimeoutMilliSeconds属性设为负数则不会自动关闭,只能通过CloseButton关闭),各种颜色,字体等。另提供一个BalloonClick事件,通知外部用户点击事件。
(3)绘制CloseButton的位图时,由于图中具有透明色,因此需要在绘制时指定透明色,相当于蒙版的作用。否则透明色会被绘制到窗体上导致窗体透明那个。
(4)弹出该窗口,主要使用ShowAt()函数。里面需要一些参数。如果需要进一步设置其他属性,可以单独进行设置。
源代码的下载链接:
http://www.cnblogs.com/Files/hoodlum1980/JDL.UILib_BalloonTip_VS7.rar
编译器提示:warning treated as error,然后某个文件未生成,build中断。
这是因为项目选项中把warning级别设置为了较高的级别导致的,某些warning被当作error,从而不能生成。
解决方法是在解决方案窗口中选中项目,右键点击project,选择“属性”,在弹出的对话框中,选择左侧TreeView中的“Configuration Properties”->“C/C++l”->“General”节点,在右侧有“Treat Warnings As Errors”(将警告当作错误对待)选项。我们把该项该为NO即可。即把相应命令行的"/WX"改为"/W"。
相应的编译选项如下:(参考MSDN)
/w 禁止所有警告
/Wn 指定显示的最高等级警告。有效等级是0~4。0级禁止所有警告。4级显示所有警告。
/Wall 使能所有警告。
/WX 视所有警告为错误。
/wln 将某个指定警告视为某个级别。第一个参数是新的级别,第二个参数是警告号码。例如/w14326 使 C4326成为1级警告。
/wdn 禁止某特定警告。n是警告号。例如, /wd4326 禁止C4326警告。
/wen 将某个指定警告视为错误。n是警告号。例如, /we4326 把 C4326 视为错误。
/won 某警告仅仅报告一次。例如:wo4326使C4326仅仅报告一次。
摘要: 摘要: 最近有感于部分网友对高斯模糊滤镜的研究,本文将对高斯模糊中半径值的含义以及高斯模糊模板尺寸的疑惑做出总结和解答。 阅读全文
摘要: 在上一篇文章中,我们介绍了开发Photoshop滤镜插件最基本的一些概念和基础。Ps为了满足插件的应用需求,同时也给插件提供了大量的回调函数(或服务)。例如,滤镜可以在一次调用后,保存最近一次用户设置的参数,并应用到下次调用或显示UI。这就是通过Ps的回调函数完成的。这一篇文章我们将讲解最重要的一些Ps回调函数。了解本文之后,我们将能够使用回调函数,完成例如存储我们的滤镜参数等必要的工作。本篇文章将比第一篇复杂和深入的多,但同时从这篇文章我们也可以一窥PS内部的秘密:缜密的系统设计,完善的接口以及复杂的工作机制。 阅读全文
摘要: 在flyweight模式,指的是具有大量的轻量级对象,我们为这些对象建立一个实体对象,其他则为“虚像”或者称为对该实体的一种“引用”。在我从前的项目中,电力系统的矢量图中,有大量设备,同种类型设备采用一种符号绘制,称为图元。这里就属于一中flyweight模式应用。...... 阅读全文
摘要: Photoshop是数字图像处理的杰出软件。他允许第三方以插件形式扩展功能。本文讲解用户最为熟悉的Photoshop滤镜插件的开发,以一个水滴效果滤镜为实例,主要介绍滤镜插件的开发流程,讨论了一些比较重要的相关技术细节问题。 阅读全文
题目链接: http://acm.zju.edu.cn/show_problem.php?pid=1146
这是一道用于把数字显示成LCD样子的题目,输入每一行有两个整数,第一个整数n表示笔画大小,第二个是需要显示成LCD样子的数字。这道题没有什么太难的,但是却让我在输出格式上卡住了,始终是Presentation Error,让我百思不得其解。后来我才发现原来是因为题目叙述的不够精确,使我没有准确理解输出格式的要求,导致我每一行都多输出了一个结尾空格。找到问题后,当然立刻就AC了。代码也不具备什么含量。
由于没有什么难度的地方,并且我也加了一点点注释,所以就没什么可做更多叙述的了。这只是一道比较简单的题目,但是输出格式一定要正确理解。
 ZOL 1146 CODE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void PrintVer(int,int,char*);
void PrintHor(int,int,char*);
void PrintNumbers(int,char*);
/*LCD的字型码*/
/* -0-
1 2
-3-
4 5
-6-
*/
int LCDCODES[10][7]=
{
{1,1,1,0,1,1,1},/*0*/
{0,0,1,0,0,1,0},/*1*/
{1,0,1,1,1,0,1},/*2*/
{1,0,1,1,0,1,1},/*3*/
{0,1,1,1,0,1,0},/*4*/
{1,1,0,1,0,1,1},/*5*/
{1,1,0,1,1,1,1},/*6*/
{1,0,1,0,0,1,0},/*7*/
{1,1,1,1,1,1,1},/*8*/
{1,1,1,1,0,1,1} /*9*/
};
char c_ver='|';
char c_hor='-';
/* 两个相邻字母中间隔了一个空列 ,因此平均每个字母占据n+3列,最后一列为间隔*/
/*打印竖直笔画,n-笔画长度,section=1或者4,numbers-数字字符串*/
void PrintVer(int n,int section,char *numbers)
{
char *line;
int i,len=(n+3)*strlen(numbers);
line=(char*)malloc(len+1);
if(line==NULL)
return;
memset(line,' ',len);
for(i=0;i<strlen(numbers);i++)
{
if(LCDCODES[*(numbers+i)-'0'][section])
*(line+(n+3)*i)=c_ver;
if(LCDCODES[*(numbers+i)-'0'][section+1])
*(line+(n+3)*i+(n+1))=c_ver;
}
/*检查最后一个字符,如果没有笔画,要使\0前移2格!*/
line[len-1]='\0';
/*打印n行*/
for(i=0;i<n;i++)
printf("%s\n",line);
free(line);
}
/*打印水平笔画,n-笔画长度,section=0,3,or 6,numbers-数字字符串*/
void PrintHor(int n,int section,char *numbers)
{
char *line;
int i,len=(n+3)*strlen(numbers);
line=(char*)malloc(len+1);
if(line==NULL)
return;
memset(line,' ',len);
for(i=0;i<strlen(numbers);i++)
{
if(LCDCODES[*(numbers+i)-'0'][section])
memset((line+(n+3)*i+1),c_hor,n);
}
/*注意最后一个数字后面无需空格了!所以多缩进一个位置*/
line[len-1]='\0';
/*打印1行*/
printf("%s\n",line);
free(line);
}
/* Print A set of Numbers : "23456" e.g. */
void PrintNumbers(int n,char *numbers)
{
PrintHor(n,0,numbers); /* ---- */
PrintVer(n,1,numbers); /* | | */
PrintHor(n,3,numbers); /* ---- */
PrintVer(n,4,numbers); /* | | */
PrintHor(n,6,numbers); /* ---- */
}
int main()
{
char line[20];
char *str1,*numbers,*delim=" ";
int n;
do
{
gets(line);
str1=strtok(line,delim);
numbers=strtok(NULL,delim);
n=atoi(str1);
if(n<=0)
break;
PrintNumbers(n,numbers);
/*每两行数字之间有一个空行*/
printf("\n");
}
while(1);
}
/*--------------------------------------------------
打印后正确的输出格式应该类似下面这样:(@表示行尾)
- - - - @
| | | | | | | | @
- - - - @
| | | | | | |@
- - - - @
----------------------------------------------------*/
|