|
|
2008年7月4日
摘要:  这里主要是我最近一段时间在中国编程论坛中发表的C语言板块的帖子和回帖等,主要选取了我个人发表的一些原创C语言代码(全部采用TC2.0进行编译),有少量属于我的一部分研究和学习过程中写的非原创性代码在说明文件中有注明,还有很多比较优秀的我收集的代码,因为并非我的原创而不位于该压缩包内。OUTPUT文件夹中有一部分代码的编译结果,对代码这里就不再一一讲解了。 阅读全文
(1)已知一个位图句柄(HBITMAP),如何获取位图的宽度和高度?
在C#中非常简单,只需要直接访问bitmap.Width和Height属性即可。
在Platform SDK中,GetBitmapDimensionEx是不能完成这个功能的(它需要事先调用SetBitmapDimensionEx),
而使用GetObject函数来获取GDIOBJECT的信息,如下代码:
HBITMAP hBitmap;
BITMAP bminfo;
GetObject(hBitmap, sizeof(BITMAP), &bminfo);
从 bminfo.bmWidth 以及 bmHeight属性可以得到。
(2)如何从一个本地文件路径加载一个HBITMAP?
LoadBitmap可以从HINSTANCE中加载位图资源,但是无法从文件名中加载。要完成这个任务,需要使用LoadImage。
例如:
char* strFileName="c:\\a.bmp";
HBITMAP hBitmap= (HBITMAP)LoadImage(NULL, strFileName, IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
但LoadImage函数只能加载BMP文件,无法成功加载JPG格式。如果要加载JPG格式,应使用OleLoadPicturePath获取一个IPicture接口对象,调用其Render函数在指定的DC进行绘制。
(3)如何使ActiveX控件重绘?
要使在IE中的ActiveX控件,可以调用this->FireViewChange();
(to be continued...)
摘要: 本文分析了系统设计师教程中的数据结构章节的部分代码,并分析和图解了对树和图两种基本数据结构的遍历。 阅读全文
发布一个在wince操作系统下,采用.net compact framework 1.0 ( c#)开发的矢量图控件,我于2007年3月份集中一个月的经历完成了它。当然,它的前身是2005年12月我写的第一个矢量图控件,在后来我在此基础上改进了很多地方,针对具体应用做了重新设计并集中精力把它完成,由于属于再次设计,因此它的架构设计和编码中凝聚了我此前开发中的经验和积累,它是我当时最满意的一个模块,对它的架构和可维护性以及运行性能都感到令我感到非常满意,可以说代表了我当时的最高水平。当然从今天来看里面还有一些缺点和经验不足之处。
例子代码我命名为GisCtl,是因为它原本是希望完成GIS的功能,但是实际上距离GIS还有一定的距离和偏差。该模块的底层算法和全部编码全部是我独自设计,这其中涉及了一系列图形捕捉算法,图元几何变换和逆变换,图层管理,缩略图,视图参数缓存环形队列,文件格式定义和IO等等。在编写该模块中的一些算法时我积累了很厚的演算草稿纸,用到了很多数学和几何知识,当然也感谢飘渺水云间BBS上ZOL版一些热心网友的支持和对我的解答。在编写这个模块时,涉及到一些设计模式,数据结构,算法的应用,比如鼠标在图上点击选择对象时,有一系列判别算法。比如图元和链接对象采用了是类似flyweight模式以节省内存(在我的另一篇随笔《图元几何变换与flyweight模式》中有讲解),比如视图缓存采用了环形的数据结构(在《环形视图堆栈》中有讲述),比如导航图采用了观察者(订阅)模式。该模块的使用方法集中在例子里,这里就不再叙述了。文档说明还暂时不能提供。目前该模块能读写我的自定义格式图形文件,以及mif格式文件。由于需求,该控件没有包装例如用鼠标创建,拖曳,变换对象的操作,但可以用代码来实现这些功能。
这个模块属于我实际工作的项目的一部分。我希望它能发挥更大的价值,而不仅仅是沉寂。
该模块文件名是LineViewCtl.dll, 命名控件是LineViewLib;该dll位于压缩包内,项目中也附带了两个从实际系统中导出的图形文件。
在模拟器中运行的效果图:(由于模拟器不支持中文,所以中文没能正确显示)

范例代码:
http://files.cnblogs.com/hoodlum1980/JRL_GisCtlDemo.rar
GisCtlDemo.rar
这是一个小的例子在于演示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);
|