Thursday, June 11, 2009

GetDeviceVersion() in RAPI fix

I have got a desktop application that determines the operating system's version of the device (I have used a Windows Mobile 5.0 device) connected to PC via ActiveSync. When calling the method GetDeviceVersion() exposed in the RAPI class in the OpenNETCF.Desktop.Communication library, the application crashes with the following exceptions:

When running the solution in Debug configuration:
System.NullReferenceException was unhandled
Message="Object reference not set to an instance of an object."


When running the solution in Release configuration:
System.AccessViolationException was unhandled
Message="Attempted to read or write protected memory. This is often an indication that other memory is corrupt."


When running the exe application:
Unhandled exception at 0x00000000 in XXXApplicationNameXXX.exe: 0xC0000005: Access violation reading location 0x00000000.

The solution to any of these issues is to PInvoke the method CeGetVersionEx() rather than the one provided in the RAPI class.

//PInvoke Declarations

[StructLayout(LayoutKind.Sequential,

    CharSet = CharSet.Unicode)]

public struct CEOSVERSIONINFO

{

    internal int dwOSVersionInfoSize;

    public int dwMajorVersion;

    public int dwMinorVersion;

    public int dwBuildNumber;

    public PlatformType dwPlatformId;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]

    public string szCSDVersion;

}

 

[DllImport("rapi.dll",

    CharSet = CharSet.Unicode,

    SetLastError = true)]

internal static extern int

    CeGetVersionEx(ref CEOSVERSIONINFO lpVersionInformation);



//PInvoke Call

CEOSVERSIONINFO osVersionInfo = new CEOSVERSIONINFO();

CeGetVersionEx(ref osVersionInfo);



Source: opennetcf

Thursday, May 28, 2009

Adding the XML Declaration when calling DataSet.WriteXml(Stream stream) method

using (DataSet ds = new DataSet())

{

//TODO: fill the ds with appropriate data

XmlTextWriter stream = new

XmlTextWriter(@"C:/xmltest.xml", Encoding.UTF8);

ds.WriteXml(stream);

stream.Close();

}



The above example attempts to write the content of the DataSet to an xml file using the DataSet.WriteXml method. The xml file doesn't contain the XML declaration.

Content of xml file:

<NewDataSet />



TIP: To include the XML declaration in the output file, call the method WriteStartDocument() on the stream object prior to the WriteXml() method call.

using (DataSet ds = new DataSet())

{

//TODO: fill the ds with appropriate data

XmlTextWriter stream = new

XmlTextWriter(@"C:/xmltest.xml", Encoding.UTF8);

stream.WriteStartDocument();

ds.WriteXml(stream);

stream.Close();

}



Content of xml file:

<?xml version="1.0" encoding="utf-8"?>

<NewDataSet />

Sunday, May 24, 2009

Application Settings in .Net Framework

The .Net Framework allows us to create and access values that persist from application session to application session. These values are called settings.For example, settings can be used to store user preferences, color scheme of application, or web server address used by the application.

Settings have four properties: Name (also used to access it at run-time), Type (represents type of setting), Value and Scope (can be either User or Application). A setting with Application scope represents a value that is used by the entire application regardless of the user, whereas a setting with User scope is more likely to be user-specific.

Application settings are read-only and values can be changed at design time, while User settings can be changed at run-time as well.

The Settings Editor in Visual Studio can be opened by double click Settings.settings under the Properties folder in Solution Explorer.



Loading settings at run-time

this.Title = Properties.Settings.Default.ApplicationName;

txtName.Text = Properties.Settings.Default.Name;

txtAddress.Text = Properties.Settings.Default.Address;

txtNationality.Text = Properties.Settings.Default.Nationality;

Saving user setings at run-time

Properties.Settings.Default.Name = txtName.Text;

Properties.Settings.Default.Nationality = txtNationality.Text;

Properties.Settings.Default.Address = txtAddress.Text;

Properties.Settings.Default.Save();



Download Example

Thursday, May 14, 2009

Single Instance applications using WindowsFormsApplicationBase available in Microsoft.VisualBasic.dll

Have you ever thought of using the WindowsFormsApplicationBase class (available in Microsoft.VisualBasic.dll) in a C# solution to implement a Single Instance application?

Actually, there are a number of ways to write Single Instance applications, such as Mutexes, Processes and so on and so forth. However, the WindowsFormsApplicationBase class provides a very elegant way to achieve the same result.

Click here, here and here for some cool examples and as such, I don't need to write any sample code and/or demo here ;-)

Tuesday, April 21, 2009

Smart Device CAB Project includes wrong localized resources

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=117453

When the projects in Visual Studion 2005 are compiled, different satellite assemblies are normally generated in different folders e.g. \obj\release\<%lang%>\ where <%lang%> can be fr, gb and pt, just to mention a few.

The INF file contents will also point to the different resource aseemblies for each resource. (though the name of these assemblies are same, the path are still different). However, I think the CabWiz.exe believes that all these assemblies are same (as they share the same name), and hence include the same assembly in the cab file for each different language.

The issue and workarounds described in the above link.

Friday, February 27, 2009

Run an application when device connects to PC via ActiveSync

To run an application when a PDA device connects to the PC via ActiveSync, the AutoStartOnConnect registry key can be used. The key resides at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\AutoStartOnConnect in the Windows Registry Editor.

When a device connects to the PC, ActiveSync enumerates all the string values under the AutoStartOnConnect key and attempts to launch the specified applications.

Similarly, the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\AutoStartOnDisconnect can be used when a device is disconnected from the PC.


Wednesday, February 4, 2009

Coding Style: WaitCursor encapsulation

Often during long processes, we need to display the WaitCursor to give feedback to the users. Changing the mouse cursor to WaitCursor, and then back to the default cursor may be achieved as follows:

1 // change to WaitCursor

2 Cursor.Current = Cursors.WaitCursor;

3

4 // DO SOMETHING

5

6 // change to default cursor

7 Cursor.Current = Cursors.Default;



Now, assume that an exception is thrown during the processing (i.e. DO SOMETHING), the cursor may never change back to the default state. Hence, we may need to use a try and finally block to ensure that the cursor is changed back when either the processing is successfully completed or an exception is thrown. The code will now be as follows:

1 // change to WaitCursor

2 Cursor.Current = Cursors.WaitCursor;

3

4 try

5 {

6 // DO SOMETHING

7 }

8 finally

9 {

10 // change to default cursor

11 Cursor.Current = Cursors.Default;

12 }



As changing the cursor to the busy state and back to the normal state is repeated in different methods, a further improvement would be to encapsulate this piece of functionality in a class. Then, a using statement can be used to handle the cursor states during processing.

23 /// <summary>

24 /// Handles wait cursor

25 /// </summary>

26 public class WaitCursor : IDisposable

27 {

28 public WaitCursor()

29 {

30 Cursor.Current = Cursors.WaitCursor;

31 }

32

33 public void Dispose()

34 {

35 Cursor.Current = Cursors.Default;

36 }

37 }




1742 using (new WaitCursor())

1743 {

1744 // DO SOMETHING

1745 }