Monday, February 7, 2011

Windows CE 5.0, VS2008

This was my first attempt at a Windows CE application. The CE device was a WASP WDT3200 barcode scanner. I hadn't done much mobile development, but I was familiar enough to know I would probably need an SDK and an emulator for testing, so I started Googling.

After some research, I downloaded and installed the Windows CE Standard SDK 5.0 – I determined the CE version by checking the Properties of the WDT3200 from My Device, which essentially equates to My Computer. Although Windows CE is a kernel and can be configured by OEMs as needed and their specific SDKs deployed, the Windows CE Standard SDK worked well enough for my needs. I also discovered the Standalone CE Emulator, but I didn't really need it. Finally, I found ActiveSync, which is required to deploy an application to a Windows CE device from Windows XP.

After installing the CE Standard SDK, I started Visual Studio and selected Project > Smart Device > Smart Device Project. I think the default project type was for Windows Mobile (what's the difference?), but if you right click on the project you can Change the Target Platform. Setting this to Windows CE changed the Look and Feel of the forms, etc.

Coding was pretty much the same as regular, thanks to the .NET CF. There are obviously differences between CF and full-blown .NET, but I didn't run into any of them because the application was pretty simple.

When deploying the application, I received an error message relating to a .NET CF not installed condition. Turns out the Devices tab of the Project Properties Page has a "Deploy the latest version of the .NET Compact Framework (including Service Packs)" checkbox that, well, does just that.

There was some bootstrapping I wanted to do during application startup, but I didn't find the application events in CF, so I wrote a main(args) method and used the Application.Run(FormObject) method. Seemed to work just fine.

I configured the barcode reader to append a Tab character to the input from the scanner, so that when a scan is completed, the Tab will move the focus to the next field. This worked pretty well for changing focus of text fields, but I ran into a problem when the next object in the tab sequence was a button. The click event would fire when the button received focus. I worked around this by setting the TabStop property of the buttons to False.

And that's basically it. My next step is to figure out the syncing from WASP to PC. That will be a separate blog post.

Thursday, January 27, 2011

RegEx and Loops Containing a Certain Word

I found myself in a situation where I had to search loops in VB.NET that contained a collection modification operation, like .Add( ) or .Delete( ). I thought this would be an ideal job for regular expressions, so off I went.

After reading and struggling for a day, this is what I finally came up with, thanks to the help of some co-workers:

(?si)(for\ each\ |while|do\ )(.(?!(next|end while|loop)))+(delete|add|remove|modify|append)+(.(?!(next|end while|loop)))+

So, taking it section by section...

(?si) : This is the options block. We have turned on Case Insensitivity and Single Line, which says the dot operator will match all characters, including CR/LF.

(for\ each\ |while|do\ ) : This block searches for a For Each / While / Do loop keyword.

(.(?!(next|end while|loop)))+ : This block searches for any characters excluding Next / End While / Loop ending keywords. This prevents us from running from one loop to the next. There are ambiguity issues with improper matching a loop opening keyword with the wrong loop ending keyword, but this was close enough for my purposes.

(delete|add|remove|modify|append)+ : This block searches for any of the words Delete / Add / Remove / Modify / Append, one or more occurrences.

(.(?!(next|end while|loop)))+ : This block searches for any characters that are not the words Next / End While / Loop. Again, not perfect, but close enough for my purposes.

So that's it, that's how I ran it. I did have some false positive matches, but searching this way was way easier than manually searching through the code base. Plus I learned more about regular expressions, which will definitely come in handy later. The entire operation was done in Expresso, very handy for validating what you think you are doing versus what you are *really* doing, and viewing the results of your regex.

Tuesday, December 21, 2010

Aspects and AOP

Aspects and AOP

Aspect Oriented Programming (AOP) is a paradigm that separates supporting functionality from business logic. It is useful for addressing Cross Cutting Concerns.

AOP is generally implemented by defining code that executes before, around, and/or after a point in business code. For example, you could define some code to execute (which is known as advice) every time a method is accessed. This code could log access, check permissions, pretty much anything you want it to do.

In the .NET world, AOP is accomplished via Attribute Programming, using a 3rd party assembly for functionality. The biggest example I found in the community was PostSharp, which I used to implement security checks in sample code. PostSharp will intercept calls to a method, property, class, etc and perform the advice as needed. So a pseudo-example might be:

<SecurityAspect(RoleEnum.Manager)> _
Public Sub GiveRaiseTo(Employee as Employee)

So what's with the SecurityAspect attribute?

Well, it would look something like this:

Public Class SecurityAspect
    Inherits MethodInterceptionAspect

Private _role As RoleEnum

    Public Sub New(Role as RoleEnum)
        _role = Role
    End Sub


 

    Public Overrides Sub OnInvoke(args as MethodInterceptionArgs)
        If Not User.Role.Equals(_role) Then
            Throw New InvalidAccessException("You are not allowed here!")

        Else
            MyBase.Invoke(args)

End If
End Sub

End Class

So what is happening here? Whenever any consuming code calls GiveRaiseTo(), the Aspect is going to execute and test the User Role against the Role that was passed in, and throw an exception if they don't match. That means, in this instance, only Managers can access the GiveRaiseTo() method.

Read more on PostSharp here.

Thursday, November 11, 2010

DataGridView WordWrap

To get cell text to word wrap is easy once you know the combination of properties to set:

DataGridView > AutoSizeRowsMode = AllCells
DataGridView > Columns > *Your Column* > Default Cell Style > Wrap Mode = True
DataGridView > Columns > *Your Column* > AutoSizeMode = DisplayedCells

Friday, October 29, 2010

Using UsageMode to Determine Design Time or Run Time

During design time editing of forms with custom user controls on them, strange errors began popping up relating to StructureMap. The issue is well documented on the internet, and is caused by controls firing the constructor when their parent form is opened in design mode. (A great explanation is provided here.) Since we had data access code in the constructor of the custom control which needed StructureMap initialized, but the Bootstrapper had not yet been called, the code would error out.

In order to work around this issue, I began testing for System.ComponentModel.UsageMode.Runtime(or DesignTime).

Thursday, September 30, 2010

Visual Studio Keyboard Shortcuts

I will be adding to this as I find them. Keep in mind these can be configured, and may not be the same on all systems...

Expand Region Under Cursor: CTL + M, CTL + O
Toggle Region Under Cursor: CTL + M, CTL + M

Monday, September 13, 2010

BinaryFormatter & “Invalid number of fixups”

While working with clsClaim (which inherits from clsGenericCollection(Of clsNCPDP)) on the Billing Screen, I was receiving the following error when deserializing:

The ObjectManager found an invalid number of fixups. This This usually indicates a problem in the Formatter.

The issue here is that, when binary serialization occurred, the object type was saved with the binary data. In this case, the object type was Classes.clsGenericCollection`1[Classes.clsNCPDP]. When deserialization occurs, the object type is attempted instantiated. Because we changed namespaces, this object is no longer valid.

The solution was to create a SerializationBinder object that dictates which type to bind to. The interesting code is:

Public
Overrides
Function BindToType(ByVal assemblyName As
String, ByVal typeName As
String) As System.Type

If typeName.Contains("Classes.clsNCPDP") Then

typeName = typeName.Replace("Classes.clsNCPDP", "BioWoRx.BusinessLogic.clsNCPDP")


 

End
If


 

If typeName.Contains("Classes.clsGenericCollection") Then

typeName = typeName.Replace("Classes.clsGenericCollection", "BioWoRx.BusinessLogic.clsGenericCollection")


 

End
If


 

Return Type.GetType(String.Format("{0}, {1}", typeName, assemblyName))


 

End
Function


 

This code is used in the application like so:


 

theFormatter.Binder = New GenericCollectionOfNcpdpBindingRedirect()

claim_fields = CType(theFormatter.Deserialize(theStream), clsGenericCollection(Of clsNCPDP))