Monday, August 25, 2008

Correct Use of the SetFont() Function in MFC

Correct Use of the SetFont() Function in MFC


http://support.microsoft.com/kb/85518

SUMMARY

The SetFont() member function of the CWnd class changes the font in a specified control. For this function to work correctly in a Windows- based application, you must ensure that the CFont object specified in the SetFont() call is not destroyed until after the specified control has been destroyed.

Back to the top

MORE INFORMATION

The SetFont() accepts a CFont object as a parameter; the control uses the specified font to display its text. The SetFont() function is implemented to send a WM_SETFONT message to the control with the font handle that corresponds to the CFont object.

An application can delete the font specified in a WM_SETFONT message only under certain circumstances; these same restrictions apply to the CFont object specified in a SetFont() call.

Specifically, do not destroy the specified CFont object until after the CWnd control has been destroyed. Windows does not copy the font specified in a SetFont() call. If the font is destroyed before the control is destroyed, unpredictable results can occur.

For example, when an application uses SetFont() to change the font a dialog box uses, the application should not destroy the CFont object until after it has destroyed the dialog box. Make the CFont object a member variable of the derived dialog box class instead of making the font a local variable in one of the functions in the class. This is the best method to ensure that the CFont object exists for the lifetime of the dialog box. When the application destroys the dialog box, the dialog box class destructor automatically calls the CFont destructor to delete the font handle.

The best time to specify the font for any controls in the dialog box is in the OnInitDialog() member function.

The code below demonstrates deriving a dialog box class from CModalDialog and using the SetFont() member function:

Back to the top

Sample Code

/*
* Compiler options needed: None
*/

class CMyAboutBox : public CDialog
{
CFont m_font;

public:
// Constructor -- This code assumes a dialog box
// template named "ABOUTDLG" in the application's .RC file.

CMyAboutBox(CWnd* pParentWnd = NULL) :
CModalDialog("ABOUTDLG", pParentWnd) {};

BOOL OnInitDialog();
};

// OnInitDialog() function -- Called after Windows creates
// the dialog box but before it is painted on the screen.

BOOL CMyAboutBox::OnInitDialog()
{
LOGFONT lf; // Used to create the CFont.

CDialog::OnInitDialog(); // Call default ::OnInitDialog

memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
lf.lfHeight = 20; // Request a 20-pixel-high font
strcpy(lf.lfFaceName, "Arial"); // with face name "Arial".
m_font.CreateFontIndirect(&lf); // Create the font.

// Use the font to paint a control. This code assumes
// a control named IDC_TEXT1 in the dialog box.
GetDlgItem(IDC_TEXT1)->SetFont(&m_font);

return TRUE;
}

Back to the top


APPLIES TO
Microsoft Foundation Class Library 4.2, when used with:
Microsoft C/C++ Professional Development System 7.0
Microsoft Visual C++ 1.0 Professional Edition
Microsoft Visual C++ 1.5 Professional Edition
Microsoft Visual C++ 1.51
Microsoft Visual C++ 1.52 Professional Edition
Microsoft Visual C++ 1.0 Professional Edition
Microsoft Visual C++ 2.0 Professional Edition
Microsoft Visual C++ 2.1
Microsoft Visual C++ 4.0 Standard Edition

Back to the top

Keywords:
kbinfo kbuidesign KB85518

Thursday, August 21, 2008

How to detect key press like:Ctrl + Enter

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
//MessageBox.Show("e.KeyData:" + e.KeyData.ToString() + "-e.KeyCode:" + e.KeyCode.ToString() + "-e.Modifiers:" + e.Modifiers.ToString() + "-e.KeyValue:" + e.KeyValue.ToString());

if (e.KeyData == (Keys.Control | Keys.Enter))
MessageBox.Show("Ctrl+Enter!");
}


Note:

You can check for Ctrl inside the KeyPress event by using the static
properties Control.ModifierKeys
In theory you should be able to do

if(e.KeyChar == (char)13 && Control.ModifierKeys == Keys.Ctrl)

Except this doesn't work. Modifierkeys are translated to characters
inside the KeyPress event. When you hold ctrl while clicking Enter
(char)10 is sent instead of (char)13 and the Control click is suppressed,
so all you have to do to detect Ctrl+Enter is

if(e.KeyChar == (char)10)

The same goes for other combinations like

if(e.KeyChar == (char)97) // [A]
if(e.KeyChar == (char)1 ) // [CTRL]+[A]

To detect key combinations put something like this inside the KeyPress
event

MessageBox.Show(((int)e.KeyChar).ToString());

But to detect, you have to use

if (e.KeyData == (Keys.Control | Keys.Enter))

Tuesday, August 19, 2008

How to set command line argument in dialog based program?

Use GetCommandLine function as following:

BOOL CColdBootApp::InitInstance()
{
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
LPTSTR lCmd = ::GetCommandLine();

// MessageBox(NULL, lCmd, L"", MB_OK);

if(_tcscmp(lCmd, L"/nobar")==0)
{
//cold boot
// MessageBox(NULL, L"Cold boot now!", L"", MB_OK);
ColdReboot();
return FALSE;
}

CColdBootDlg dlg;
m_pMainWnd = &dlg;

int nResponse = dlg.DoModal();
...


}

(
CString aa = ::GetCommandLine();
aa.MakeLower();
BOOL bShowBar = FALSE;
BOOL bDoAsk = FALSE;
if(aa.Find(L"/nobar")==-1)
bShowBar = TRUE;
else
bShowBar = FALSE;

if(aa.Find(L"/noask")==-1)
bDoAsk = TRUE;
else
bDoAsk = FALSE;

if(bDoAsk)
{
if(MessageBox(NULL, L"Are you sure?", L"Cold Boot", MB_YESNOCANCEL|MB_TOPMOST|MB_ICONEXCLAMATION )!=IDYES)
return FALSE;
else
{
if(!bShowBar)
{
ColdReboot();
return FALSE;
}
}
}else
{
if(!bShowBar)
{
ColdReboot();
return FALSE;
}
}
)
//*************How to use command line exe file**********************//
/*
C# 5.0:
// Run the CAB
Process CabRunner = Process.Start( "wceload" , "/noui " + CABFile );
CabRunner.WaitForExit();

C# 4.0:
// Used to create a new process.
[DllImport("Coredll", EntryPoint="CreateProcess", SetLastError=true)]
private static extern Int32 CreateProcess(
string sImageName,
string sCmdLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
Int32 boolInheritHandles,
Int32 dwCreationFlag,
IntPtr lpEnvironment,
IntPtr lpCurrentDir,
byte[] si,
ProcessInfo pi);
public IntPtr OpenExternalProgram(string sExeName, string sCmdLine)
{
byte[] b = new byte[128];
ProcessInfo pi = new ProcessInfo();

try
{
// Create a new process that opens the external (exe) program.
CreateProcess(sExeName, sCmdLine, IntPtr.Zero, IntPtr.Zero, 0, 0, IntPtr.Zero, IntPtr.Zero, b, pi);
return pi.hProcess;
}
catch
{
return IntPtr.Zero;
}
}
C++:
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));

STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);

if(::CreateProcess(_T("\\ColdBoot.exe"), _T(""), NULL, NULL, NULL, FALSE, 0, NULL, &si, &pi) != 0)
{
::WaitForSingleObject(pi.hProcess, 300L); // wait to its finish
::CloseHandle(pi.hProcess);
}else
MessageBox(NULL,L"WarmReboot failed!",L"",MB_OK);

*/

Tuesday, August 5, 2008

阴历规则

[声明]: 以下资料摘自http://thunder.cwru.edu/ccal/rule.htm [孟卓(zhuo@thunder.cwru.edu)]

阴历规则

中国的阴历,又称农历,大家应该都很熟悉。很多的传统节日,像春节,中秋都是阴历的节日。不过,若是问起阴历的规则,怕是知道的人就不多了。多数人知道初 一是新月出现的那一天,月圆的那一天则在十五左右。不少人也知道二十四节气在阳历的每月中大概的日期。再细节的概念如闰月对大多数人则不甚了解了。本人经 过一番查找与阅读,终于对阴历的规则有了一定的认识。在此愿与大家分享。

首先阴历以月为基本单位,一个月以新月出现的那一天为始直至下一个新月出现的前一天。由于月亮公转的周期介于29到30天之间,阴历的一个月也就由新月出 现时刻的早晚或是29天或是30天。大月为30天,小月为29天。与阳历不同的是,大小月在不同的年中不固定。如春节的前一天常称为大年三十,但有不少年 如2000年的阴历十二月只有29天。由于十二个月的时间较阳历年即地球绕太阳公转一周的时间短11天左右,为了使阴历年与阳历年保持相对稳定,每隔两三 年就需要加入一个闰月。大约每十九年要加入七个闰月。而二十四节气则是由地球在绕太阳公转的轨道上的位置确定的。以每年的冬至为始,每15度为一个节气。 是故二十四节气在阳历的每月中有大概固定的日期。古时以二十四节气指导农耕,这就是阴历又称农历的原因。其中阳历下半月的十二个节气又称为中气。中气出现 的时刻和闰月的确定有直接的关系。

中国阴历的计算有下列几条规则:

  • 所有新月和节气出现时刻的计算以北京时间为准。现北京时间为东经120度即东八区标准时。但计算1929年以前的阴历时应以北京即东经116度25分的当地时为准。此条规则用以区分中国阴历和其他类似阴历如日本阴历。
  • 一天始自夜里零时。尽管旧时的子时相当于现今的23时至1时,但是子时的上四刻属于前一天,下四刻才属于新的一天,所以和现今一天始自零时的定义是一致的。
  • 新月出现的一天为一个月的第一天。如某个节气的出现时刻也在这一天,则不论该节气的出现时刻是否比新月晚,一律算落入新的一个月中。
  • 每年的冬至总是出现在这年的阴历十一月中。
  • 从一年的冬至后一天起到下一年冬至这一天止的这段时间中,下称其间,如有十三个新月出现,则其间要加入一个闰月。需要加入闰月时,其间第一个没有 中气的月为闰月。因为其间只有十二个中气,所以其间至少有一个月没有中气,也存在有两个月没有中气的可能性。但这种情况下只有第一个没有中气的月为闰月。 闰月的前一个月为几月则该闰月称为闰几月。

以上所列的阴历的计算规则是在清朝顺治年间,即公元1645年,开始采用的。以上规则的一个重要特点就是理论上完全以天文观测为依据,其中没有任何 数学关系。这和阳历,即格里历,完全是由数学关系确定的形成了鲜明的对比。当然,具体到未来阴历的计算,仍然需要月亮与地球运动的数学模型,而且精度高的 这种数学模型相当复杂,在没有电脑的情况下,一般人根本不可能推算出精确的阴历来。而阳历的数学关系则非常简单,是不是闰年很容易计算。这又形成了另外一 种鲜明的对比。

Friday, August 1, 2008

evc4工程移植vs.net2005所碰到的问题积累

在移植项目前,建议还是看看以下的文章:

循序渐进:将 eMbedded Visual C++ 应用程序迁移到 Visual Studio 2005
eMbedded Visual C++ 到 Visual Studio 2005 升级向导(注意其最后一句话:默认情况下,Embedded Visual C++ 4.0 版会将 MFC Pocket PC 应用程序的对话框样式(Border)设置为 DS_MODALFRAME。MFC 8.0 不支持此样式。 —— 应改为Thin,如果不改的话,窗口就无法弹出。)
从 eVC 移植所带来的已知问题
Migrating Microsoft eMbedded Visual C++ Projects to Visual Studio 2005
开发环境:Windows XP +SP2, Visual Studio 2005 professional, Windows Mobile 6.0 Professional SDK。
注:(1)对于Windows Mobile 5.0 SDK 开发的程序在Windows Mobile 6.0 下也能运行,而且不需要对程序进行任何的修改。
(2)由于有些错误,是环境配置问题,所以在Debug/Resease模式下,都需要进行修改,以下错误中,如果是这类错误,都在标号后面写着 “Resealse 模式也需要改”,当天切换到别的SDK下,如Windows Mobile 5.0 SDK,也需要修改。
以下是针对Debug模式下的:

1、StdAfx.cpp (Resealse 模式也需要改)
编译错误:D:Program FilesMicrosoft Visual Studio 8VCceatlmfcincludeafxver_.h(77) : fatal error C1189: #error : Please use the /MD switch for _AFXDLL builds
解决方法:右击工程名,打开Project properties对话框,切换到C/C++->Code generation页,将Runtime Libarary 设置成“Multi-threaded DLL(/MD)”,即可解决此问题。

2、编译错误:error C2065: 'i' : undeclared identifier
原因:是由于存在以下的代码段:
for (int i = 0; i < MAX_LEN; i ++)
{
//……
}
for (i = 0; i < MAX_NUM; i ++)
{
//……
}
对于evc离开循环后,循环变量仍然有效,并且仍可以使用,但是在VS2005下是不行的,由此可见VS2005对变量的定义与审查更为严格,还有就是对数组越界问题也比EVC来的强。
解决方法:(不能完全相信编译器,也不能把所有的语法检查都丢给编译器)
int i = 0;
for (i = 0; i < MAX_LEN; i ++)
{
//……
}
for (i = 0; i < MAX_NUM; i ++)
{
//……
}

3、error C2664: '_wcsnicmp' : cannot convert parameter 2 from 'LPWORD' to 'const wchar_t *'
需要强制类型转换。

4、error C2061: syntax error : identifier 'HELPINFO'
自己增加HELPINFO的类型,增加头文件HelpInfo.h。

5、error C2146: syntax error : missing ';' before identifier 'm_wndCommandBar'
原因:在Windows Mobile 5.0/6.0 下CCeCommandBar类被CCommandBar替换
解决方法:
CCeCommandBar m_wndCommandBar; ---- 〉CCommandBar m_wndCommandBar;

6、error C2065: 'NUM_TOOL_TIPS' : undeclared identifier
解决:
//#if defined(_WIN32_WCE_PSPC) && (_WIN32_WCE >= 212)
#define NUM_TOOL_TIPS 8
//#endif

7、error C3861: 'ON_WM_HELPINFO': identifier not found
同 4

8、error C2440: 'static_cast' : cannot convert from 'void (__cdecl CMyAppView::* )(void)' to 'LRESULT (__cdecl CWnd::* )(WPARAM,LPARAM)'None of the functions with this name in scope match the target type
解决方法:
afx_msg void OnHotLinkExplain(); --- 〉
afx_msg LRESULT OnHotLinkExplain(WPARAM wParam,LPARAM lParam);

9、error C2664: 'CSize CDC::GetTextExtent(LPCTSTR,int) const' : cannot convert parameter 1 from 'WORD *' to 'LPCTSTR'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast需要强制转换
pDC->GetTextExtent(&i, 1).cx); ——>
pDC->GetTextExtent((LPCTSTR)&i, 1).cx;

10、error C2039: 'OnHelpInfo' : is not a member of 'CView'
error C2039: 'OnHelpInfo' : is not a member of 'CFrameWnd'
error C2039: 'OnHelpInfo' : is not a member of 'CDialog'
解决方法:用TRUE替换相应的类成员函数OnHelpInfo'
return CView::OnHelpInfo(pHelpInfo); ——> return TRUE;

11、error C2039: 'm_bShowSharedNewButton' : is not a member of 'CCommandBar'
D:Program FilesMicrosoft Visual Studio 8VCceatlmfcincludeafxext.h(557) : see declaration of 'CCommandBar'
解决方法:
直接注释掉 m_wndCommandBar.m_bShowSharedNewButton = FALSE;

12、MyApp.rc(380) : fatal error RC1015: cannot open include file 'wceres.rc'.
解决方法:
直接注释掉:#include "wceres.rc" // WCE-specific components
但是,这个错误很讨厌,每次你修改资源文件后,都得修改该语句,不知道为什么。

13、Resease 模式下也要修改
error LNK2019: unresolved external symbol SHInitExtraControls referenced in function "protected: __cdecl CMyAppView::CMyAppView(void)" ( 0CMyAppView@@IAA@XZ)
问题:程序中调用了SHInitExtraControls();
error LNK2019: unresolved external symbol SHSipPreference referenced in function "protected: void __cdecl CMyAppView::OnKillfocusWord(void)" ( OnKillfocusWord@CMyAppView@@IAAXXZ)
问题:程序中调用了SHSipPreference
以上两个函数都在:Library: aygshell.lib里
解决方法:
工程-->属性-->Linker -->input -- > Additional Denpendencies :aygshell.lib

14、Resease 模式下也要修改
orelibc.lib(wwinmain.obj) : error LNK2019: unresolved external symbol wWinMain referenced in function wWinMainCRTStartup
属性—〉Linker—〉Anvanced—〉EntryPoint
将 wWinMainCRTStartup 更改为 WinMainCRTStartup
Entry Point是WinMainCRTStartup(ANSI)或wWinMainCRTStartup(UINCODE),即: ... WinMainCRTStartup 或wWinMainCRTStartup 会调用WinMain 或wWinMain。

15、 error C3861: 'LoadStdProfileSettings': identifier not found
注释掉函数 LoadStdProfileSettings;
该函数的具体功能,看MSDN。
BTW:编译的时候,有可能会出现一些由以上错误产生的连锁错误,俗称“蝴蝶效应”,如error C2143: syntax error : missing ';' before '}'
error C2143: syntax error : missing ';' before ','
error C2143: syntax error : missing ';' before '{'
少了了'{'、'}'、';'等等,把以上的错误—主要矛盾解决了,这些错误—错误矛盾也就迎刃而解了。何况,这个工程是以前在EVC IDE下编译通过,MS再怎么优化或改进编译器,也总不可能发生自相矛盾的事情吧,总要考虑兼容性吧,要对自己或公司的前辈有信心!
到此,已经能够编译通过,但是运行的时候,又出现如下的问题:

16、Resease 模式下也要修改
按F5,出现如下的对话框:

解决方法:
右击工程的属性—〉General—〉Project Defaults –〉Use MFC :
Use MFC in a shared DLL ——> Use MFC in a static DLL
也正是因为这个,VS2005产生的EXE程序比EVC产生的要大200多k。

这样,程序基本移植完成,但是还要把所有的功能过一遍,有可能还会碰到,诸如对话框出现乱码、菜单不对等问题。


[收集FROM 蓝天清水博客]
在将evc4的工程移植到.net2005时会碰到很多问题,以下只是其中我遇到的一些问题的摘录以及相关的处理结果:

1.首先在将EVC4的工程转化成.net2005时要将工程的属性中的c/c++->代码生成->运行时库改为:多线程DLL(/MD)

2.在工程的属性中的链接器->高级->入口点改为:WinMainCRTStartup

3.遇到stdafx.cpp
_CE_ACTIVEX was not defined because this Windows CE SDK does not have DCOM.
_CE_ACTIVEX could be caused to be defined by defining _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA, but it is recommended that this be done only for single-threaded apps.
_ATL_NO_HOSTING was defined because _CE_ACTIVEX was not defined.
的错误:在stdafx.h文件里加上#define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA可解决.

4.遇到StdAfx.cpp
WINVER not defined. Defaulting to 0x0501
在工程的属性c/c++->预处理器->预处理器定义中加上_WIN32_WINNT=0x500试试