Problems porting an API call from VB6 to C#
-
In VB6 I was able to use MCM_SETFIRSTDAYOFWEEK to set Monday as the first day of the week in the DateTimePicker calendar (in the dtp.DropDown event). My attempts to port the same API call to the C# version have been unsuccessful; it compiles and runs, but it doesn't change the first day of the week in the calendar. I've included both the VB6 and C# code below. (Note: the declarations and DropDown code are in the same form). 'VB6
'**************************************************************************
'Needed for DateTimePicker calendar "first day of week"
Const DTM_FIRST = &H1000
Const DTM_GETMONTHCAL = DTM_FIRST + 8
Const MCM_FIRST = &H1000
Const MCM_SETFIRSTDAYOFWEEK = MCM_FIRST + 15Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, ByVal lParam As Any) As Long
'**************************************************************************In the VB6 DTPicker DropDown event
'Get a reference to the handle of the DateTimePicker control
lCalHwnd = SendMessage(ctlDateTimePicker.hWnd, DTM_GETMONTHCAL, 0&, ByVal 0&)'Send an API message to change the presentation
' lCalHwnd = handle to the control
' MCM_SETFIRSTDAYOFWEEK = Flag for message to send
' 0& = Unused parameter
' 0& = Day of week (0 = Monday … 6 = Sunday)
SendMessage lCalHwnd, MCM_SETFIRSTDAYOFWEEK, 0&, ByVal 0&// C#
//*************************************************************************
// Needed for DTPicker calendar "first day of week"
private const int DTM_FIRST = 0x1000;
private const int DTM_GETMONTHCAL = DTM_FIRST + 8;
private const int MCM_FIRST = 0x1000;
private const int MCM_SETFIRSTDAYOFWEEK = MCM_FIRST + 15;[DllImport("user32.dll",EntryPoint="SendMessageA")]
extern static IntPtr SendMessageFirstDayOfWeek(IntPtr hWnd, int wMsg, int wParam, int lParam);
//*************************************************************************In the C# DateTimePicker DropDown event
// Send an API message to change the presentation
// dtpStartDate.Handle = handle to the control
// MCM_SETFIRSTDAYOFWEEK = Flag for message to send
// 0 = Unused parameter
// 0 = Day of week (0 = Monday … 6 = Sunday)
SendMessageFirstDayOfWeek(dtpStartDate.Handle, MCM_SETFIRSTDAYOFWEEK, 0, 0);Any help would be greatly appeciated!
-
In VB6 I was able to use MCM_SETFIRSTDAYOFWEEK to set Monday as the first day of the week in the DateTimePicker calendar (in the dtp.DropDown event). My attempts to port the same API call to the C# version have been unsuccessful; it compiles and runs, but it doesn't change the first day of the week in the calendar. I've included both the VB6 and C# code below. (Note: the declarations and DropDown code are in the same form). 'VB6
'**************************************************************************
'Needed for DateTimePicker calendar "first day of week"
Const DTM_FIRST = &H1000
Const DTM_GETMONTHCAL = DTM_FIRST + 8
Const MCM_FIRST = &H1000
Const MCM_SETFIRSTDAYOFWEEK = MCM_FIRST + 15Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, ByVal lParam As Any) As Long
'**************************************************************************In the VB6 DTPicker DropDown event
'Get a reference to the handle of the DateTimePicker control
lCalHwnd = SendMessage(ctlDateTimePicker.hWnd, DTM_GETMONTHCAL, 0&, ByVal 0&)'Send an API message to change the presentation
' lCalHwnd = handle to the control
' MCM_SETFIRSTDAYOFWEEK = Flag for message to send
' 0& = Unused parameter
' 0& = Day of week (0 = Monday … 6 = Sunday)
SendMessage lCalHwnd, MCM_SETFIRSTDAYOFWEEK, 0&, ByVal 0&// C#
//*************************************************************************
// Needed for DTPicker calendar "first day of week"
private const int DTM_FIRST = 0x1000;
private const int DTM_GETMONTHCAL = DTM_FIRST + 8;
private const int MCM_FIRST = 0x1000;
private const int MCM_SETFIRSTDAYOFWEEK = MCM_FIRST + 15;[DllImport("user32.dll",EntryPoint="SendMessageA")]
extern static IntPtr SendMessageFirstDayOfWeek(IntPtr hWnd, int wMsg, int wParam, int lParam);
//*************************************************************************In the C# DateTimePicker DropDown event
// Send an API message to change the presentation
// dtpStartDate.Handle = handle to the control
// MCM_SETFIRSTDAYOFWEEK = Flag for message to send
// 0 = Unused parameter
// 0 = Day of week (0 = Monday … 6 = Sunday)
SendMessageFirstDayOfWeek(dtpStartDate.Handle, MCM_SETFIRSTDAYOFWEEK, 0, 0);Any help would be greatly appeciated!
In you're code you're not using the
MonthCalendar
control'sHandle
like you are in your VB6 code. You must get the handle to the calendar first:using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
class DTPSample : Form
{
DateTimePickerEx dtp;
[STAThread]
static void Main()
{
Application.Run(new DTPSample());
}
DTPSample()
{
dtp = new DateTimePickerEx();
Controls.Add(dtp);
dtp.FirstDayOfWeek = DayOfWeek.Monday;
dtp.Location = new Point(8, 8);
Text = "DTP Sample";
}
}
public class DateTimePickerEx : DateTimePicker
{
const int DTM_GETMONTHCAL = 0x1008;
const int MCM_SETFIRSTDAYOFWEEK = 0x100f;
DayOfWeek firstDayOfWeek;
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam,
IntPtr lParam);
public DateTimePickerEx()
{
}
/// <summary>Gets a handle to the month calendar when displayed.</summary>
public IntPtr MonthCalendar
{
get
{
if (IsHandleCreated)
{
return SendMessage(Handle, DTM_GETMONTHCAL,
IntPtr.Zero, IntPtr.Zero);
}
return IntPtr.Zero;
}
}
[DefaultValue(DayOfWeek.Sunday)]
public DayOfWeek FirstDayOfWeek
{
get { return firstDayOfWeek; }
set
{
bool fireEvent = firstDayOfWeek != value;
firstDayOfWeek = value;
if (fireEvent)
OnFirstDayOfWeekChanged(EventArgs.Empty);
}
}
public event EventHandler FirstDayOfWeekChanged;
protected virtual void OnFirstDayOfWeekChanged(EventArgs e)
{
if (FirstDayOfWeekChanged != null)
FirstDayOfWeekChanged(this, e);
}
protected override void OnDropDown(EventArgs e)
{
base.OnDropDown(e);
if (MonthCalendar != IntPtr.Zero)
{
SendMessage(MonthCalendar, MCM_SETFIRSTDAYOFWEEK, IntPtr.Zero,
new IntPtr(firstDayOfWeek == DayOfWeek.Sunday ? 6 :
(int)firstDayOfWeek - 1));
}
}
}Also notice how I declare
SendMessage
usingCharSet=CharSet.Auto
in theDllImportAttribute
. This will append "A" and "W" for the appropriate functions when necessary. This helps to produce robust assemblies. Declaring the parameters as the correct type - in this case, bothwParam
-
In you're code you're not using the
MonthCalendar
control'sHandle
like you are in your VB6 code. You must get the handle to the calendar first:using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
class DTPSample : Form
{
DateTimePickerEx dtp;
[STAThread]
static void Main()
{
Application.Run(new DTPSample());
}
DTPSample()
{
dtp = new DateTimePickerEx();
Controls.Add(dtp);
dtp.FirstDayOfWeek = DayOfWeek.Monday;
dtp.Location = new Point(8, 8);
Text = "DTP Sample";
}
}
public class DateTimePickerEx : DateTimePicker
{
const int DTM_GETMONTHCAL = 0x1008;
const int MCM_SETFIRSTDAYOFWEEK = 0x100f;
DayOfWeek firstDayOfWeek;
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam,
IntPtr lParam);
public DateTimePickerEx()
{
}
/// <summary>Gets a handle to the month calendar when displayed.</summary>
public IntPtr MonthCalendar
{
get
{
if (IsHandleCreated)
{
return SendMessage(Handle, DTM_GETMONTHCAL,
IntPtr.Zero, IntPtr.Zero);
}
return IntPtr.Zero;
}
}
[DefaultValue(DayOfWeek.Sunday)]
public DayOfWeek FirstDayOfWeek
{
get { return firstDayOfWeek; }
set
{
bool fireEvent = firstDayOfWeek != value;
firstDayOfWeek = value;
if (fireEvent)
OnFirstDayOfWeekChanged(EventArgs.Empty);
}
}
public event EventHandler FirstDayOfWeekChanged;
protected virtual void OnFirstDayOfWeekChanged(EventArgs e)
{
if (FirstDayOfWeekChanged != null)
FirstDayOfWeekChanged(this, e);
}
protected override void OnDropDown(EventArgs e)
{
base.OnDropDown(e);
if (MonthCalendar != IntPtr.Zero)
{
SendMessage(MonthCalendar, MCM_SETFIRSTDAYOFWEEK, IntPtr.Zero,
new IntPtr(firstDayOfWeek == DayOfWeek.Sunday ? 6 :
(int)firstDayOfWeek - 1));
}
}
}Also notice how I declare
SendMessage
usingCharSet=CharSet.Auto
in theDllImportAttribute
. This will append "A" and "W" for the appropriate functions when necessary. This helps to produce robust assemblies. Declaring the parameters as the correct type - in this case, bothwParam
Your example worked great! I see now that I was trying to use the handle to the DateTimePicker instead of the MonthCalendar component. I still don't completely understand the code, but it will give me something to study. Thank you for the help!