Wednesday, May 23, 2007

MessageBox with more options in C#

MessageBox in C# does not provide a lot of options as in C++. Following is the example to add these option back:

using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;

namespace XXX
{
public class MessageBoxAdvanced
{
#region WINUSER CONSTS
// From winuser.h
public const uint MB_OK = 0x00000000;
private const uint MB_OKCANCEL = 0x00000001;
private const uint MB_ABORTRETRYIGNORE = 0x00000002;
private const uint MB_YESNOCANCEL = 0x00000003;
public const uint MB_YESNO = 0x00000004;
private const uint MB_RETRYCANCEL = 0x00000005;
private const uint MB_HELP = 0x00004000;

private const uint MB_USERICON = 0x00000080;

private const uint MB_ICONHAND = 0x00000010;
private const uint MB_ICONQUESTION = 0x00000020;
private const uint MB_ICONEXCLAMATION = 0x00000030;
private const uint MB_ICONASTERISK = 0x00000040;
private const uint MB_ICONWARNING = MB_ICONEXCLAMATION;
private const uint MB_ICONERROR = MB_ICONHAND;
private const uint MB_ICONINFORMATION = MB_ICONASTERISK;
private const uint MB_ICONSTOP = MB_ICONHAND;

private const uint MB_DEFBUTTON1 = 0x00000000;
private const uint MB_DEFBUTTON2 = 0x00000100;
private const uint MB_DEFBUTTON3 = 0x00000200;

private const uint MB_RTLREADING = 0x00100000;
private const uint MB_DEFAULT_DESKTOP_ONLY = 0x00020000;
private const uint MB_SERVICE_NOTIFICATION = 0x00200000; // assumes WNT >= 4
private const uint MB_RIGHT = 0x00080000;

public const uint MB_APPLMODAL = 0x00000000;
public const uint MB_SYSTEMMODAL = 0x00001000;
private const uint MB_TASKMODAL = 0x00002000;

public const uint MB_TOPMOST =0x00040000;

// For setting window icon.
private const uint WM_SETICON = 0x00000080;
private const uint ICON_SMALL = 0;
private const uint ICON_BIG = 1;

private const int WH_CBT = 5;

private const int HCBT_CREATEWND = 3;

private const int IDOK = 1;
private const int IDCANCEL = 2;
private const int IDABORT = 3;
private const int IDRETRY = 4;
private const int IDIGNORE = 5;
public const int IDYES = 6;
public const int IDNO = 7;

#endregion

[DllImport("coredll.dll")]
public static extern int MessageBox(int hWnd, String sMessage, String sTitle, uint type);
}
}

* For .Net CF

Error Report Example in C#

public class CreateErrorLog
{
#region Variables
private string m_sLogFormat;
private string m_sErrorTime;
#endregion

#region Properties
//get and set - public access of private members
public string LogFormat
{
get
{
return m_sLogFormat;
}
set
{
m_sLogFormat = value;
}
}
public string ErrorTime
{
get
{
return m_sErrorTime;
}
set
{
m_sErrorTime = value;
}
}
#endregion

#region Constructor
public CreateErrorLog()
{
// TODO: Add constructor logic here
m_sLogFormat = "[2T]"+ DateTime.Now.ToShortDateString().ToString()+" "+DateTime.Now.ToLongTimeString().ToString()+" ==> ";
string sYear = DateTime.Now.Year.ToString();
string sMonth = DateTime.Now.Month.ToString();
string sDay = DateTime.Now.Day.ToString();
m_sErrorTime = sYear+sMonth+sDay;
}
~CreateErrorLog(){}
#endregion

#region Functions
public void ErrorLog(string sPathName, string sErrMsg)
{
StreamWriter sw = File.AppendText(sPathName+m_sErrorTime+".txt");
sw.WriteLine(m_sLogFormat + sErrMsg);
sw.Flush();
sw.Close();
}
#endregion
}

Error Report Example in C++

#ifndef __ERRORREPORT_H__
#define __ERRORREPORT_H__

#define ERRORREPORTFILE "SystemCF\\ErrorLog.txt"

// Add a message to ErrorLog.txt file
// cMsg: the input message
// Return TRUE if it is success, FALSE otherwise
BOOL RecordErrMsg(LPCSTR cMsg)
{
// Open file
FILE* stream =fopen(ERRORREPORTFILE, "a" );
if(NULL==stream) return(FALSE);

// Save the time and data
CTime t = CTime::GetCurrentTime();
int iMonth=t.GetMonth();
int iDay=t.GetDay();
int iHour=t.GetHour();
int iMinute=t.GetMinute();
int iSecond=t.GetSecond();
fprintf( stream, "%d:%d:%d On %d/%d\n", iHour, iMinute, iSecond, iMonth, iDay);

// Save error message
fprintf( stream, "%s\n\n", cMsg);

// Close file
int iReturn=fclose(stream);
if(EOF==iReturn) return(FALSE);

return(TRUE);
}

// Add a message to ErrorLog.txt file
// cMsg: the input message
// Return TRUE if it is success, FALSE otherwise
BOOL RecordErrMsg(LPCTSTR cMsg)
{
// Open file
FILE* stream =fopen(ERRORREPORTFILE, "a" );
if(NULL==stream) return(FALSE);

// Save the time and data
CTime t = CTime::GetCurrentTime();
int iMonth=t.GetMonth();
int iDay=t.GetDay();
int iHour=t.GetHour();
int iMinute=t.GetMinute();
int iSecond=t.GetSecond();
fprintf( stream, "%d:%d:%d On %d/%d\n", iHour, iMinute, iSecond, iMonth, iDay);

// Save error message
_ftprintf( stream, _T("%s\n\n"), cMsg);

// Close file
int iReturn=fclose(stream);
if(EOF==iReturn) return(FALSE);

return(TRUE);
}

// Add a message to a file with the current time mask
// cMsg: the input message
// Return TRUE if it is success, FALSE otherwise
BOOL RecordMsg(LPCSTR filePath, LPCTSTR cMsg)
{
// Open file
FILE* stream =fopen(filePath, "a" );
if(NULL==stream) return(FALSE);

// Save the time and data
CTime t = CTime::GetCurrentTime();
int iMonth=t.GetMonth();
int iDay=t.GetDay();
int iHour=t.GetHour();
int iMinute=t.GetMinute();
int iSecond=t.GetSecond();
fprintf( stream, "%d:%d:%d On %d/%d\n", iHour, iMinute, iSecond, iMonth, iDay);

// Save error message
_ftprintf( stream, _T("%s\n\n"), cMsg);

// Close file
int iReturn=fclose(stream);
if(EOF==iReturn) return(FALSE);

return(TRUE);
}

// Add a message to a file with the input time mask
// cMsg: the input message
// CTime: the time record
// Return TRUE if it is success, FALSE otherwise
BOOL RecordMsg(LPCSTR filePath, LPCTSTR cMsg, CTime t)
{
// Open file
FILE* stream =fopen(filePath, "a" );
if(NULL==stream) return(FALSE);

// Save the time and data
int iMonth=t.GetMonth();
int iDay=t.GetDay();
int iHour=t.GetHour();
int iMinute=t.GetMinute();
int iSecond=t.GetSecond();
fprintf( stream, "%d:%d:%d On %d/%d\n", iHour, iMinute, iSecond, iMonth, iDay);

// Save error message
_ftprintf( stream, _T("%s\n\n"), cMsg);

// Close file
int iReturn=fclose(stream);
if(EOF==iReturn) return(FALSE);

return(TRUE);
}

// Add a message to a file without a time mask
// cMsg: the input message
// Return TRUE if it is success, FALSE otherwise
BOOL RecordMsg_NoTime(LPCSTR filePath, LPCTSTR cMsg)
{
// Open file
FILE* stream =fopen(filePath, "a" );
if(NULL==stream) return(FALSE);

// Save error message
_ftprintf( stream, _T("%s\n\n"), cMsg);

// Close file
int iReturn=fclose(stream);
if(EOF==iReturn) return(FALSE);

return(TRUE);
}

// Record the current memory
BOOL PrintMem(LPCTSTR cMsg, BOOL bEnd)
{
MEMORYSTATUS stat;
GlobalMemoryStatus (&stat);

// Open file
FILE* stream = fopen("\\SystemCF\\testMessage.txt", "a" );
if(NULL==stream) return(FALSE);

//print the message
_ftprintf(stream, _T("%s\n"), cMsg);

// fprintf(stream, "There are %12.5f total MB of physical memory\n", stat.dwTotalPhys/(1024.0 * 1024.0));

fprintf(stream, "There are %12.5f free MB of physical memory.\n", stat.dwAvailPhys/(1024.0 * 1024.0));

// fprintf(stream, "There are %12.5f total MB of virtual memory.\n", stat.dwTotalVirtual/(1024.0 * 1024.0));

if(TRUE==bEnd)
{
fprintf(stream, "There are %12.5f free MB of virtual memory.\n\n",
stat.dwAvailVirtual/(1024.0 * 1024.0));
}
else
{
fprintf(stream, "There are %12.5f free MB of virtual memory.\n",
stat.dwAvailVirtual/(1024.0 * 1024.0));
}

Sleep(100);
// Close file
int iReturn=fclose(stream);
if(EOF==iReturn) return(FALSE);

return(TRUE);
}

#endif //__ERRORREPORT_H__

Ascii to Hex in C#

try
{
int iTemp = 0;
string sTemp = "";
string strHex;
foreach (char c in txtKeyA.Text)
{
iTemp = c;
strHex = String.Format("{0:x2}", (uint)System.Convert.ToUInt32(iTemp.ToString()));
// MessageBox.Show(strHex);
sTemp = sTemp + strHex;
}
txtKeyA.Text = sTemp;
this.btnToHex.Enabled = false;
this.btnToAscii.Enabled = true;
}
catch(Exception eE)
{
// MessageBox.Show(eE.ToString());
MessageBox.Show("Failed to convert!!! Please check your input format!");
}

Hex to Ascii Conversion in C#

try
{
int n =0;
string temp;
string temp2 = "";
for(int i = 0; i {
temp = txtKeyA.Text.Substring(i,2);
n = Convert.ToInt32(temp, 16);
//To convert it to a character, simply cast the integer to char
temp2 = temp2 + ((char)n).ToString();
}
txtKeyA.Text = temp2;
this.btnToHex.Enabled = true;
this.btnToAscii.Enabled = false;
}
catch(Exception eE)
{
// MessageBox.Show(eE.ToString());
MessageBox.Show("Failed to convert!!! Please check your input format!");
}

C# File Open, Save in .Net Framework and Compact Framework

let's do C#:

1. Compact Framework:

private void btnOpenFile_Click(object sender, System.EventArgs e)
{
System.Windows.Forms.OpenFileDialog fd = new System.Windows.Forms.OpenFileDialog();
fd.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
fd.FilterIndex = 1;

if(fd.ShowDialog() == DialogResult.OK)
{
MessageBox.Show(fd.FileName);
// Insert code to read the stream here.
StreamReader str = new StreamReader(fd.FileName);

string tmp = str.ReadLine();
while(tmp!=null)
{
MessageBox.Show(tmp);
tmp = str.ReadLine();
}
str.Close();
}

}

private void btnSaveFile_Click(object sender, System.EventArgs e)
{
System.Windows.Forms.SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
sfd.FilterIndex = 1;
if(sfd.ShowDialog() == DialogResult.OK)
{
MessageBox.Show(sfd.FileName);
string sfn = sfd.FileName;
if(sfn.Length > 4)
{
string sTmpFN = sfn.Substring(sfn.Length-4, 4);
MessageBox.Show(sfd.FileName);
if(sTmpFN != ".txt" )
sfn = sfn + ".txt";
}else
sfn = sfn + ".txt";
MessageBox.Show(sfn);
StreamWriter sw = new StreamWriter(sfn);
sw.WriteLine("Something!");
sw.Close();
}
}

2. .Net Framework:
private void button2_Click(object sender, System.EventArgs e)
{
Stream st;
System.Windows.Forms.OpenFileDialog fd = new System.Windows.Forms.OpenFileDialog();
fd.CheckPathExists = true;
fd.CheckFileExists = true;
fd.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
fd.FilterIndex = 1;
fd.RestoreDirectory = true;

if(fd.ShowDialog() == DialogResult.OK)
{
MessageBox.Show(fd.FileName);

if((st = fd.OpenFile())!= null)
{
// Insert code to read the stream here.
StreamReader str = new StreamReader(fd.FileName);

string tmp = str.ReadLine();
while(tmp!=null)
{
MessageBox.Show(tmp);
tmp = str.ReadLine();
}
str.Close();
st.Close();
}
}

}

private void button3_Click(object sender, System.EventArgs e)
{
System.Windows.Forms.SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
sfd.FilterIndex = 1;
if(sfd.ShowDialog() == DialogResult.OK)
{
MessageBox.Show(sfd.FileName);
StreamWriter sw = new StreamWriter(sfd.FileName);
sw.WriteLine("Something!");
sw.Close();
}
}

C++ File Open, save in .Net Compact Framework

Since we are talking about folder browsing, we can review how to do file saving and opening.

First, small device...

void CXXDlg::OnBnClickedBtnConfig()
{
// TODO: Add your control notification handler code here

TCHAR tFileName[MAX_PATH+1] = TEXT("\0");

OPENFILENAME ofn;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = this->m_hWnd;
ofn.lpstrFile = tFileName;
ofn.lpstrFilter = TEXT("Cam Config\0*.c2t\0All Files (*.*)\0*.*\0");
ofn.nFilterIndex = 0;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrInitialDir = TEXT("\\SystemCF");
ofn.lpstrTitle = TEXT("Cam Config File Open Dialog");
ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
ofn.lpstrDefExt = TEXT("c2t");

GetOpenFileName(&ofn);

sStatus.Format(_T("%s"),tFileName );
UpdateData(FALSE);

}

similar, GetSaveFileName(..)..

How to do a folder browing in .Net Compact Framework?

Under investigation, will post the result later...

Folder Browsing --- Easy way 2

Chris Anderson suggested to use FolderNameEditor which in System.Design.dll
 public class BrowseForFolder : FolderNameEditor
{
// inherit the FolderNameEditor class
FolderNameEditor.FolderBrowser fBrowser;

public BrowseForFolder()
{
// contructor
// create an instance of FolderBrowser
fBrowser = new System.Windows.Forms.Design.FolderNameEditor.FolderBrowser();
}

public string ShowIt(string textdescription)
{
// set the Description label
fBrowser.Description = textdescription;
fBrowser.ShowDialog(); // show the Windows
return fBrowser.DirectoryPath;// return whatever path choosen
}
~BrowseForFolder()
{
// destructor
fBrowser.Dispose();
}
}

Usage:
BrowseForFolder test = new BrowseForFolder();
string sPath = test.ShowIt("Easyone!");

MessageBox.Show(sPath);

Key: you have to reference the System.Design.dll (C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322)to be able to access the FolderNameEditor namespace.

Note: still not available for Compact Framework.

Folder Browsing --- Easy way 1

For .Net Framework, use FolderBrowserDialog:

System.Windows.Forms.FolderBrowserDialog fbd = new FolderBrowserDialog();
fbd.ShowNewFolderButton = false;
fbd.Description = "Please select a folder.";
fbd.RootFolder = System.Environment.SpecialFolder.DesktopDirectory ;
fbd.SelectedPath = "apps"; //default
if(fbd.ShowDialog()==System.Windows.Forms.DialogResult.OK)
MessageBox.Show(fbd.SelectedPath);

But , this is not available for .net Compact Framework

Microsoft way to do folder browsing

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

...

using System.Runtime.InteropServices;
using System.Text;
internal class Win32API
{
// C# representation of the IMalloc interface.
[InterfaceType ( ComInterfaceType.InterfaceIsIUnknown ),
Guid ( "00000002-0000-0000-C000-000000000046" )]
public interface IMalloc
{
[PreserveSig] IntPtr Alloc ( [In] int cb );
[PreserveSig] IntPtr Realloc ( [In] IntPtr pv, [In] int cb );
[PreserveSig] void Free ( [In] IntPtr pv );
[PreserveSig] int GetSize ( [In] IntPtr pv );
[PreserveSig] int DidAlloc ( IntPtr pv );
[PreserveSig] void HeapMinimize ( );
}

[DllImport("User32.DLL")]
public static extern IntPtr GetActiveWindow ( );

public class Shell32
{
// Styles used in the BROWSEINFO.ulFlags field.
[Flags]
public enum BffStyles
{
RestrictToFilesystem = 0x0001, // BIF_RETURNONLYFSDIRS
RestrictToDomain = 0x0002, // BIF_DONTGOBELOWDOMAIN
RestrictToSubfolders = 0x0008, // BIF_RETURNFSANCESTORS
ShowTextBox = 0x0010, // BIF_EDITBOX
ValidateSelection = 0x0020, // BIF_VALIDATE
NewDialogStyle = 0x0040, // BIF_NEWDIALOGSTYLE
BrowseForComputer = 0x1000, // BIF_BROWSEFORCOMPUTER
BrowseForPrinter = 0x2000, // BIF_BROWSEFORPRINTER
BrowseForEverything = 0x4000, // BIF_BROWSEINCLUDEFILES
}

// Delegate type used in BROWSEINFO.lpfn field.
public delegate int BFFCALLBACK ( IntPtr hwnd, uint uMsg, IntPtr lParam, IntPtr lpData );

[StructLayout ( LayoutKind.Sequential, Pack=8 )]
public struct BROWSEINFO
{
public IntPtr hwndOwner;
public IntPtr pidlRoot;
public IntPtr pszDisplayName;
[MarshalAs ( UnmanagedType.LPTStr )]
public string lpszTitle;
public int ulFlags;
[MarshalAs ( UnmanagedType.FunctionPtr )]
public BFFCALLBACK lpfn;
public IntPtr lParam;
public int iImage;
}

[DllImport ( "Shell32.DLL" )]
public static extern int SHGetMalloc ( out IMalloc ppMalloc );

[DllImport ( "Shell32.DLL" )]
public static extern int SHGetSpecialFolderLocation (
IntPtr hwndOwner, int nFolder, out IntPtr ppidl );

[DllImport ( "Shell32.DLL" )]
public static extern int SHGetPathFromIDList (
IntPtr pidl, StringBuilder Path );

[DllImport ( "Shell32.DLL", CharSet=CharSet.Auto )]
public static extern IntPtr SHBrowseForFolder ( ref BROWSEINFO bi );
}
}
...



Very Complicated!!!

How to do a folder browsing in C#?

For C++, we all know that "SHBrowseForFolder" can be used to browse folder. For example:

//include Ceshell.lib in the lib
BROWSEINFO bi = { 0 };
bi.lpszTitle = _T("Please select a directory to store pictures!");
LPITEMIDLIST pidl = SHBrowseForFolder ( &bi );
if ( pidl != 0 )
{
CString sPath;
TCHAR* buf = sPath.GetBuffer(MAX_PATH);
SHGetPathFromIDList(pidl, buf); //get a full path

sStatus.Format(_T("%s"),buf );
UpdateData(FALSE);

// free memory used
IMalloc * imalloc = 0;
if ( SUCCEEDED( SHGetMalloc ( &imalloc )) )
{
imalloc->Free ( pidl );
imalloc->Release ( );
}
}

But how to do it in C#? It seems this part is missing?