| Code: |
//set irda service status HRESULT OBEXIOCTL(DWORD dwIOCTL) { HANDLE hService; BOOL fRet; hService = CreateFile(TEXT("OBX0:"),GENERIC_READ|GENERIC_WRITE,0, NULL,OPEN_EXISTING,0,NULL); if (INVALID_HANDLE_VALUE == hService) { CloseHandle(hService); return FALSE; } fRet = DeviceIoControl(hService,dwIOCTL,0,0,0,0,NULL,0); CloseHandle(hService); return (0 == fRet)?E_FAIL:S_OK; } //query irda service status DWORD OBEXQuery() { HANDLE hService; BOOL fRet; DWORD dwStatus; hService = CreateFile(TEXT("OBX0:"),GENERIC_READ|GENERIC_WRITE,0, NULL,OPEN_EXISTING,0,NULL); if (INVALID_HANDLE_VALUE == hService) { CloseHandle(hService); return FALSE; } fRet = DeviceIoControl(hService,IOCTL_SERVICE_STATUS,0,0,&dwStatus,sizeof(DWORD),0, 0); CloseHandle(hService); if(0 == fRet) return 0xFFFFFFFF; else return dwStatus; } bool GetIRDAState() { switch(OBEXQuery()) { case SERVICE_STATE_SHUTTING_DOWN: case SERVICE_STATE_UNLOADING: case SERVICE_STATE_UNINITIALIZED: case SERVICE_STATE_OFF: return 0; break; case SERVICE_STATE_STARTING_UP: case SERVICE_STATE_ON: return 1; break; default: break; }; return 0; } |
Monday, October 20, 2008
How to control bluetooth OBEX default service on/off?
Friday, October 10, 2008
C# TrayIcon Class
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32;
using System.Windows.Forms;
namespace XXXX
{
public class TrayIcon
{
//Declare click event
public event System.EventHandler Click;
private WindowSink windowSink;
private int uID = 11000;
//Constructor
public TrayIcon()
{
//Create instance of the MessageWindow subclass
windowSink = new WindowSink(this);
windowSink.uID = uID;
}
//Destructor
~TrayIcon()
{
Remove();
}
public void Add(IntPtr hIcon)
{
TrayMessage(windowSink.Hwnd, NIM_ADD, (uint)uID, hIcon);
}
public void Remove()
{
TrayMessage(windowSink.Hwnd, NIM_DELETE, (uint)uID, IntPtr.Zero);
}
public void Modify(IntPtr hIcon)
{
TrayMessage(windowSink.Hwnd, NIM_MODIFY, (uint)uID, hIcon);
}
private void TrayMessage(IntPtr hwnd, int dwMessage, uint uID, IntPtr hIcon)
{
NOTIFYICONDATA notdata = new NOTIFYICONDATA();
notdata.cbSize = 152;
notdata.hIcon = hIcon;
notdata.hWnd = hwnd;
notdata.uCallbackMessage = WM_NOTIFY_TRAY;
notdata.uFlags = NIF_MESSAGE | NIF_ICON;
notdata.uID = uID;
int ret = Shell_NotifyIcon(dwMessage, ref notdata);
}
#region API Declarations
internal const int WM_LBUTTONDOWN = 0x0201;
internal const int WM_RBUTTONUP = 0x0205;
//User defined message
internal const int WM_NOTIFY_TRAY = 0x0400 + 2001;
internal const int NIM_ADD = 0x00000000;
internal const int NIM_MODIFY = 0x00000001;
internal const int NIM_DELETE = 0x00000002;
const int NIF_MESSAGE = 0x00000001;
const int NIF_ICON = 0x00000002;
internal struct NOTIFYICONDATA
{
internal int cbSize;
internal IntPtr hWnd;
internal uint uID;
internal uint uFlags;
internal uint uCallbackMessage;
internal IntPtr hIcon;
//internal char[] szTip = new char[64];
//internal IntPtr szTip;
}
[DllImport("coredll.dll")]
internal static extern int Shell_NotifyIcon(
int dwMessage, ref NOTIFYICONDATA pnid);
[DllImport("coredll.dll")]
internal static extern int SetForegroundWindow(IntPtr hWnd);
[DllImport("coredll.dll")]
internal static extern int ShowWindow(
IntPtr hWnd,
int nCmdShow);
[DllImport("coredll.dll")]
internal static extern IntPtr GetFocus();
#endregion
#region WindowSink
internal class WindowSink : Microsoft.WindowsCE.Forms.MessageWindow
{
//Private members
private int m_uID = 0;
private TrayIcon trayIcon;
//Constructor
public WindowSink(TrayIcon tIcon)
{
trayIcon = tIcon;
}
public int uID
{
set
{
m_uID = value;
}
}
protected override void WndProc(ref Microsoft.WindowsCE.Forms.Message msg)
{
if (msg.Msg == WM_NOTIFY_TRAY)
{
switch ((int)msg.LParam)
{
case WM_LBUTTONDOWN:
if ((int)msg.WParam == m_uID)
{
//If somebody hooked, raise the event
if (trayIcon.Click != null)
trayIcon.Click(trayIcon, null);
}
break;
case WM_RBUTTONUP:
{
MessageBox.Show("R Button Up");
}
break;
}
}
}
}
#endregion
}
}
Tuesday, October 7, 2008
How to set device clock (set system time)?
To get or set the system time of the device, use platform invoke to call the native GetSystemTime or SetSystemTime functions.
Note that the GetSystemTime function returns Coordinated Universal Time (UTC, also known as Greenwich Mean Time). To get your local time, you must add or subtract the number of hours between your time zone and UTC. For example, 24:00 (midnight) in UTC is 19:00 in New York--an offset of minus 5 hours (UTC–5).
To determine the UTC offset for your time zone, see the Time Zone tab of Date and Time Properties.
Some device emulators do not initially set daylight-saving time correctly, which could affect your result.
Public Structure SYSTEMTIME
Public wYear As UInt16
Public wMonth As UInt16
Public wDayOfWeek As UInt16
Public wDay As UInt16
Public wHour As UInt16
Public wMinute As UInt16
Public wSecond As UInt16
Public wMilliseconds As UInt16
End Structure
Declare Function GetSystemTime Lib "CoreDll.dll" _
(ByRef lpSystemTime As SYSTEMTIME) As UInt32
Declare Function SetSystemTime Lib "CoreDll.dll" _
(ByRef lpSystemTime As SYSTEMTIME) As UInt32
Public Sub GetTime
' Call the native GetSystemTime method
' with the defined structure.
Dim st As New SYSTEMTIME
GetSystemTime(st)
' Show the current time.
MessageBox.Show("Current Time: " & st.wHour.ToString() _
& ":" & st.wMinute.ToString())
End Sub
Public Sub SetTime
' Call the native GetSystemTime method
' with the defined structure.
Dim st As New SYSTEMTIME
GetSystemTime(st)
' Set the system clock ahead one hour.
st.wHour = Convert.ToUInt16(((CInt(st.wHour) + 1)) Mod 24)
SetSystemTime(st)
End Sub
[DllImport("coredll.dll")]
private extern static void GetSystemTime(ref SYSTEMTIME lpSystemTime);
[DllImport("coredll.dll")]
private extern static uint SetSystemTime(ref SYSTEMTIME lpSystemTime);
private struct SYSTEMTIME
{
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMilliseconds;
}
private void GetTime()
{
// Call the native GetSystemTime method
// with the defined structure.
SYSTEMTIME stime = new SYSTEMTIME();
GetSystemTime(ref stime);
// Show the current time.
MessageBox.Show("Current Time: " +
stime.wHour.ToString() + ":"
+ stime.wMinute.ToString());
}
private void SetTime()
{
// Call the native GetSystemTime method
// with the defined structure.
SYSTEMTIME systime = new SYSTEMTIME();
GetSystemTime(ref systime);
// Set the system clock ahead one hour.
systime.wHour = (ushort)(systime.wHour + 1 % 24);
SetSystemTime(ref systime);
MessageBox.Show("New time: " + systime.wHour.ToString() + ":"
+ systime.wMinute.ToString());
}
Thursday, September 25, 2008
Copying files from Desktop to a CE device
So I have this problem, where I need to create a tool that creates a folder with a bunch of files on the PC and then copies all these files over to a CE device. The method of choice here was via ActiveSync over USB. One of the design goals was to be able to copy these files to a number of devices simultaneously. However, research revealed that this is not really possible since, activesync only supports one active connection at a time. So much for the great idea.
So now we are faced with this problem of copying files over to the device over ActiveSync. Since the app had a lot of GUI, I created that in C#. The .NET framework exposes excellent API for file manipulation based on paths. The problem with ActiveSync connections is when the device is cradled, there is no drive letter associated with the connection. So all device paths are then \My Documents\ or \Program Files\ etc.
This creates a problem as far as the File manipulation API in System.IO. Since these methods accept relative as well as fully qualified paths, any path like the above, would be treated as a relative path and not a fully qualified path, thereby causing a lot of grief.
The only way to get past this so far has been to use RAPI.
RAPI stands for Remote Application Programming Interface, and was created ages ago with the first wave of activesync and windows mobile products.
RAPI has some documentation on MSDN at: http://msdn.microsoft.com/en-us/library/aa458022.aspx
However since RAPI is a native API, almost all the documentation is geared towards native implementation.
After searching the intertubes for a suitable solution, I couldn’t find one that was recent, and that was guaranteed to work.
Below is the solution:
using System;
using System.Threading;
using System.Runtime.InteropServices;
using COMTYPES = System.Runtime.InteropServices.ComTypes;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Logger = Microsoft.MobileDevices.Tools.Utilities.Logger;
namespace Microsoft.MobileDevices.Tools.RAPILibrary
{
public class RAPILibrary
{
# region RAPI EXTERN
// -------------------------------------------------------
// RAPI.DLL Definitions
// -------------------------------------------------------
public const int MAX_PATH = 260;
public const uint MAXDWORD = 0xFFFFFFFF;
public const uint S_OK = 0;
public struct RAPIINIT
{
public int cbSize;
public IntPtr heRapiInit;
public int hrRapiInit;
};
// From WINBASE.H -- for CeCreateFile
public enum ACCESS : uint
{
READ = 0x80000000,
WRITE = 0x40000000,
}
// From WINBASE.H -- for CeCreateFile
public enum SHARE
{
READ = 0x00000001,
WRITE = 0x00000002,
}
// From WINBASE.H -- for CeCreateFile
public enum ACTION
{
CREATE_NEW = 1,
CREATE_ALWAYS = 2,
OPEN_EXISTING = 3,
OPEN_ALWAYS = 4,
TRUNCATE_EXISTING = 5
}
// From WINBASE.H -- for CeCreateFile
public enum FILEFLAGATT : uint
{
ATTRIBUTE_READONLY = 0x00000001,
ATTRIBUTE_HIDDEN = 0x00000002,
ATTRIBUTE_SYSTEM = 0x00000004,
ATTRIBUTE_DIRECTORY = 0x00000010,
ATTRIBUTE_ARCHIVE = 0x00000020,
ATTRIBUTE_INROM = 0x00000040,
ATTRIBUTE_ENCRYPTED = 0x00000040,
ATTRIBUTE_NORMAL = 0x00000080,
ATTRIBUTE_TEMPORARY = 0x00000100,
ATTRIBUTE_SPARSE_FILE = 0x00000200,
ATTRIBUTE_REPARSE_POINT = 0x00000400,
ATTRIBUTE_COMPRESSED = 0x00000800,
ATTRIBUTE_OFFLINE = 0x00001000,
ATTRIBUTE_ROMSTATICREF = 0x00001000,
ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000,
ATTRIBUTE_ROMMODULE = 0x00002000,
FLAG_WRITE_THROUGH = 0x80000000,
FLAG_OVERLAPPED = 0x40000000,
FLAG_NO_BUFFERING = 0x20000000,
FLAG_RANDOM_ACCESS = 0x10000000,
FLAG_SEQUENTIAL_SCAN = 0x08000000,
FLAG_DELETE_ON_CLOSE = 0x04000000,
FLAG_BACKUP_SEMANTICS = 0x02000000,
FLAG_POSIX_SEMANTICS = 0x01000000,
}
///
/// Closes handle passed in
///
/// handle to be closed
///
[DllImport("rapi.DLL", CharSet = CharSet.Unicode)]
public static extern int CeCloseHandle(IntPtr hObject);
///
/// Creates file on device
///
/// path of file
/// Read/Write
/// Share mode
///
/// File creation options
/// Flags and attributes
///
///
[DllImport("rapi.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr CeCreateFile(string lpFileName, ACCESS dwDesiredAccess, SHARE dwShareMode, int Res1, ACTION dwCreationDisposition, FILEFLAGATT dwFlagsAndAttributes, int Res2);
///
/// Reads the file
///
/// handle to the file
/// buffer to copy data to
/// file size to read
/// file size read
///
///
[DllImport("rapi.DLL", CharSet = CharSet.Unicode)]
public static extern int CeReadFile(IntPtr hFile, IntPtr lpBuffer, int nNumberOfBytesToRead, ref int lpNumberOfBytesRead, int Reserved);
///
/// Writes file to device
///
/// handle of file to write to
/// data to write
/// length of buffer
/// length of file on device
///
///
[DllImport("rapi.DLL", CharSet = CharSet.Unicode)]
public static extern int CeWriteFile(IntPtr hFile, IntPtr lpBuffer, int nNumberOfBytesToWrite, ref int lpNumberOfBytesWritten, int Reserved);
///
/// Copies file from desktop to device
///
/// Full path of file on the desktop including filename
/// Path of file name on the device. '\' denotes root
public static void CopyFiletoDevice(string deskFile, string devFilePath)
{
try
{
int numTries=0;
// Verify file exists on desktop
FileInfo fInfo = new FileInfo(deskFile);
if (fInfo.Exists)
{
IntPtr devFileHandle;
// create a file on the device
do // force valid handle in the loop
{
devFileHandle = CeCreateFile(devFilePath, ACCESS.READ | ACCESS.WRITE, SHARE.READ | SHARE.WRITE, 0, ACTION.CREATE_ALWAYS, FILEFLAGATT.ATTRIBUTE_NORMAL, 0);
if (devFileHandle.ToInt32() < 0)
{
CeCloseHandle(devFileHandle);
}
} while (devFileHandle.ToInt32() < 0);
// read file from desktop into a byte buffer
Byte[] buffer;
ReadFileAsBinary(deskFile, out buffer);
int numBytesWritten = 0;
unsafe
{
fixed(byte* bufferPtr = buffer)
{
int retVal = CeWriteFile(devFileHandle, (IntPtr)(bufferPtr), (int)fInfo.Length, ref numBytesWritten, 0);
if (retVal == 0)
{
throw new IOException("RAPILibrary:CopyFileToDevice() Error Writing file on device. " + CeGetLastError().ToString());
}
}
}
// close handles
CeCloseHandle(devFileHandle);
}
else
{
Logger.WriteLog("RAPILibrary:CopyFileToDevice() File does not exist on desktop: " + deskFile);
}
}
catch (IOException ioEx)
{
Logger.WriteLog(ioEx.Message);
}
catch (Exception ex)
{
Logger.WriteLog(ex.ToString());
}
}
///
/// Reads file and returns byte[]
///
/// Full path of file
/// byte array for file data
private static void ReadFileAsBinary(string path, out Byte[] buffer)
{
Logger.WriteLog("RAPILibrary:ReadFileAsBinary() Reading the file " + path);
FileInfo fInfo = new FileInfo(path);
long fileLength = fInfo.Length;
buffer = new Byte[fileLength];
FileStream fs = fInfo.OpenRead();
fs.Read(buffer, 0, (int)fileLength);
fs.Close();
Logger.WriteLog("RAPILibrary:ReadFileAsBinary() Exit");
}
}
}
Wednesday, September 10, 2008
How to create Customized Control in C#?
http://www.codeproject.com/KB/miscctrl/cutebutton.aspx
Introduction
This is a short and simple demonstration of .NET framework's capability of creating custom controls.
Here I'm going to make a custom control and then, test my control in a Windows application. I have implemented some custom properties for my control, so you can learn how it is done in C#.
Building the Control
-
Open the Visual Studio and start a new project. Your project must be based on the Windows Control Library template. Call your project ctlCuteButton and click OK.
-
Once you have your project open, delete the UserControl from the project. Just remove it because the 'User Control' is not exactly what we need here.
-
Now go to the 'Project' menu: Project->Add User Control... and select the Custom Control template there. 'Custom Control' is what we need in this case. You may call it
cuteButton. Now click OK. A new Custom control has been added to your project. -
The first thing we must do here is to change the base class of the
cuteButton:Override the following line:
public class cuteButton : System.Windows.Forms.Control
by this one:
public class cuteButton : System.Windows.Forms.Button
Now your control is based on the
System.Windows.Forms.Buttonclass. -
Now let's create some custom properties for our control. This is done by inserting the following code inside the cuteButton class:
Collapse
private Color m_color1 = Color.LightGreen; //first color
private Color m_color2 = Color.DarkBlue; // second color
private int m_color1Transparent = 64; // transparency degree
// (applies to the 1st color)
private int m_color2Transparent = 64; // transparency degree
// (applies to the 2nd color)
public Color cuteColor1
{
get { return m_color1; }
set { m_color1 = value; Invalidate(); }
}
public Color cuteColor2
{
get { return m_color2; }
set { m_color2 = value; Invalidate(); }
}
public int cuteTransparent1
{
get { return m_color1Transparent; }
set { m_color1Transparent = value; Invalidate(); }
}
public int cuteTransparent2
{
get { return m_color2Transparent; }
set { m_color2Transparent = value; Invalidate(); }
}The
Invalidate()methoid is used to refresh the design view and all controls inside (the tip from Tom Welch). -
And the last thing to do before compiling our control is to override the
Paintevent. So let's do it:// Calling the base class OnPaint
base.OnPaint(pe);
// Create two semi-transparent colors
Color c1 = Color.FromArgb(m_color1Transparent , m_color1);
Color c2 = Color.FromArgb(m_color2Transparent , m_color2);
Brush b = new System.Drawing.Drawing2D.LinearGradientBrush(ClientRectangle,
c1, c2, 10);
pe.Graphics.FillRectangle (b, ClientRectangle);
b.Dispose(); -
Now you may compile the control by pressing
+ +.
Here is the complete contents of cuteButton.cs file (just in case…)
Testing the Control
-
Open a new instance of the VS .NET. Create a new project choosing the Windows Application template.
-
From a new Windows Forms project, we can add the compiled custom control to the toolbox. I do this by right-clicking the toolbox, selecting Customize Toolbox, and from the .NET Framework Components tab, clicking Browse and locating the Control Library DLL # (in our case, ctlCuteButton\bin\debug\cuteButton.dll). The component cuteButton will then appear in the Toolbox.
You can play a bit changing it’s properties (
cuteColor1,cuteColor2,cuteTransparent1,cuteTransparent2).
That’s all so far about building and using custom controls.
Good Luck.
(Or, do not need to add control from toolbox, add the control project to your project, then the control will appear automatically.)
Thursday, September 4, 2008
Window CE, how to get File size, version information in C#?
FileInfo aa = new FileInfo("\\xxx");
aa.LastWriteTime;
aa.Length;
aa.CreationTime;
for file version, you have to use some C++ help here:
public class FileVersionInfo
{
#region Variables
private string m_sFileName;
private byte[] m_bytVersionInfo;
#endregion
#region Constants
private const int GMEM_FIXED = 0x0000;
private const int LMEM_ZEROINIT = 0x0040;
private const int LPTR = (GMEM_FIXED | LMEM_ZEROINIT);
#endregion
#region Constructors
///
/// Constructor.
///
/// File name and path.
private FileVersionInfo(string sFileName)
{
if (File.Exists(sFileName))
{
int iHandle = 0;
int iLength = 0;
int iFixedLength= 0;
IntPtr ipFixedBuffer = IntPtr.Zero;
// Get the file information.
m_sFileName = Path.GetFileName(sFileName);
iLength = GetFileVersionInfoSize(sFileName, ref iHandle);
if(iLength > 0)
{
// Allocate memory.
IntPtr ipBuffer = AllocHGlobal(iLength);
// Get the version information.
if(GetFileVersionInfo(sFileName, iHandle, iLength, ipBuffer))
{
// Get language independant version info.
if(VerQueryValue(ipBuffer, "\\", ref ipFixedBuffer, ref iFixedLength))
{
// Copy information to array.
m_bytVersionInfo = new byte[iFixedLength];
Marshal.Copy(ipFixedBuffer, m_bytVersionInfo, 0, iFixedLength);
}
}
// Free memory.
FreeHGlobal(ipBuffer);
}
}
else
{
m_bytVersionInfo = new byte[200];
}
}
#endregion
#region Properties
///
/// Get the file build part.
///
public int FileBuildPart
{
get
{
return Convert.ToInt32(BitConverter.ToInt16(m_bytVersionInfo, 14));
}
}
///
/// Get the file major part.
///
public int FileMajorPart
{
get
{
return Convert.ToInt32(BitConverter.ToInt16(m_bytVersionInfo, 10));
}
}
///
/// Get the file minor part.
///
public int FileMinorPart
{
get
{
return Convert.ToInt32(BitConverter.ToInt16(m_bytVersionInfo, 8));
}
}
///
/// Get the name of the file.
///
public string FileName
{
get
{
return m_sFileName;
}
}
///
/// Get the file private part.
///
public int FilePrivatePart
{
get
{
return Convert.ToInt32(BitConverter.ToInt16(m_bytVersionInfo, 12));
}
}
///
/// Get the product build part.
///
public int ProductBuildPart
{
get
{
return Convert.ToInt32(BitConverter.ToInt16(m_bytVersionInfo, 22));
}
}
///
/// Get the product major part.
///
public int ProductMajorPart
{
get
{
return Convert.ToInt32(BitConverter.ToInt16(m_bytVersionInfo, 18));
}
}
///
/// Get the product minor part.
///
public int ProductMinorPart
{
get
{
return Convert.ToInt32(BitConverter.ToInt16(m_bytVersionInfo, 16));
}
}
///
/// Get the product private part.
///
public int ProductPrivatePart
{
get
{
return Convert.ToInt32(BitConverter.ToInt16(m_bytVersionInfo, 20));
}
}
#endregion
#region Functions
///
/// Allocate unmanged memory.
///
/// Length to allocate.
///
private static IntPtr AllocHGlobal(int iLength)
{
return LocalAlloc(LPTR, (uint)iLength);
}
///
/// Free allocated memory.
///
/// IntPtr object to free.
private static void FreeHGlobal(IntPtr hGlobal)
{
LocalFree(hGlobal);
}
///
/// Get the file version information.
///
/// File name and path.
///
public static FileVersionInfo GetVersionInfo(string sFileName)
{
return new FileVersionInfo(sFileName);
}
#endregion
#region Win32API
[DllImport("coredll", EntryPoint="GetFileVersionInfo", SetLastError=true)]
private static extern bool GetFileVersionInfo(
string filename,
int handle,
int len,
IntPtr buffer);
[DllImport("coredll", EntryPoint="GetFileVersionInfoSize", SetLastError=true)]
private static extern int GetFileVersionInfoSize(
string filename,
ref int handle);
[DllImport("coredll.dll", EntryPoint="LocalAlloc", SetLastError=true)]
private static extern IntPtr LocalAlloc(
uint uFlags,
uint Bytes);
[DllImport("coredll.dll", EntryPoint="LocalFree", SetLastError=true)]
private static extern IntPtr LocalFree(
IntPtr hMem);
[DllImport("coredll", EntryPoint="VerQueryValue", SetLastError=true)]
private static extern bool VerQueryValue(
IntPtr buffer,
string subblock,
ref IntPtr blockbuffer,
ref int len);
#endregion
}
}
Then:
FileVersionInfo fiWindows = FileVersionInfo.GetVersionInfo(@"\Windows\sdcgina.exe");
//MessageBox.Show("1 Window:" + fiWindows.FileMajorPart + "_" + fiWindows.FileMinorPart + "_" + fiWindows.FileBuildPart + "_"
// + fiWindows.ProductMajorPart + "_" + fiWindows.ProductMinorPart + "_" + fiWindows.ProductPrivatePart + "_" + fiWindows.ProductBuildPart
// + "SystemCF:" + fiSystemCF.FileMajorPart + "_" + fiSystemCF.FileMinorPart + "_" + fiSystemCF.FileBuildPart + "_"
// + fiSystemCF.ProductMajorPart + "_" + fiSystemCF.ProductMinorPart + "_" + fiSystemCF.ProductPrivatePart + "_" + fiSystemCF.ProductBuildPart);
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
MORE INFORMATION
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:
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;
}
APPLIES TO
| • | Microsoft Foundation Class Library 4.2, when used with: | |||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||
Keywords: | kbinfo kbuidesign KB85518 |