Twips and .NET

20. September 2007 04:46 by Mrojas in General  //  Tags: , , ,   //   Comments (0)

In the VB world previous to .NET a concept you probably had to deal with was TWIPS.

What were Twips? Well if you do not remember those happy VB6 times, let me refresh your memory:

Twips are screen-independent units to ensure that the proportion of screen elements are the same on all display systems.
A twip is defined as being 1/1440 of an inch.


A Pixel is a screen-dependent unit, standing for 'picture element'.
A pixel is a dot that represents the smallest graphical measurement on a screen.

In .NET everything is pixels. So if you migrated something from VB6 using the Upgrade Wizard you might found several expressions like:

VB6.TwipsToPixelsX(ctrl.Left)

or VB6.PixelsToTwipsY(ctrl.Height)

There is an X and a Y version of this function, because the conversion factor is not the same for both axis.

Sadly you can even found some expressions like:

VB6.TwipsToPixelsX(VB6.PixelsToTwipsX(ctrl.Left))

In a strict sense there could be minor differences because of the conversion factors. But in it seams that things like that can be removed because all controls Bound properties like Left, Top, Bottom, Right are in pixels. So why will you convert your pixels units to Twips units to then convert them back to Pixels if they where already in Pixels????

Also you can find something like:

VB6.TwipsToPixelsX(ctrl.Left + ctrl.Width + 30) which should be something like:

ctrl.Left + ctrl.Width  + VB6.TwipsToPixelsX(30)

If you have an application migrated with the Upgrade Wizard you can use some regular expressions to improve those expressions. If the conversion is something like:

VB6.TwipsToPixelsY(VB6.PixelsToTwipsX(ctrl.Left)) then be careful because conversion factor might produce a different value, due to the change of axis.

 

 

jeje Or you can uset the VBCompanion, the extensible version of the Upgrade Wizard!!!

 

Casting in .NET

13. September 2007 04:20 by Mrojas in General  //  Tags: , , ,   //   Comments (0)

.NET has a more strict typing than VB6
So you must check in some circumstances if your object implements an interface or not.

So I had used the as and is operators in C# but I did not know how to do that.
I did I little research and I discovered some things about casting operators for VB.NET

 

Operator Example Observations
CType Dim testNumber As Long = 1000
' The following line of code sets testNewType to 1000.0.
Dim testNewType As Single = CType(testNumber, Single)
 
Throws InvalidCastException or OverflowException

It could be less eficient due to VB.Net helper routines.

This is a Narrowing and Widening operator.

It can be overloaded

Public Structure digit
Private dig As Byte
    Public Sub New(ByVal b As Byte)
        If (b OrElse b > 9) Then Throw New _
            System.ArgumentException("Argument outside range for Byte")
        Me.dig = b
    End Sub
    Public Shared Widening Operator CType(ByVal d As digit) As Byte
        Return d.dig
    End Operator
    Public Shared Narrowing Operator CType(ByVal b As Byte) As digit
        Return New digit(b)
    End Operator
End Structure
 

 

DirectCast Dim f As New System.Windows.Forms.Form
Dim c As System.Windows.Forms.Control
' The following conversion succeeds.
c = DirectCast(f, System.Windows.Forms.Control)
 
Throws InvalidCastException. Is more efficient than CType because it does not depend on the Visual Basic helper runtime functions. It can even detect some errors as invalid casts during compile time
 

However it requires a relationship of inheritance of implementation
For example:

Dim q As Object = 2.37
Dim i As Integer = CType(q, Integer)
' The following conversion fails at run time
Dim j As Integer = DirectCast(q, Integer)
 

The run-time type of q is Double. CType succeeds because Double can be converted to Integer. However, the first DirectCast fails at run time because the run-time type of Double has no inheritance relationship with Integer, even though a conversion exists
 

TryCast     Dim obj As MyType = TryCast(obj, MyType)
    If obj Is Nothing Then
      ' Object could not be cast
 
  Else
     ' Object was casted

   End If
Throws no exceptions.


All this information has been taken from the MSDN site. This is just a quick summary. For more information see:

Type Conversion Functions
Conversion Functions (Visual Basic)

Widening and Narrowing Conversions
Implicit and Explicit Conversions
 

Fixed Len Strings in Visual Basic

7. September 2007 09:34 by Mrojas in General  //  Tags: , , ,   //   Comments (0)

This is a nostalgic note. Someone asked me, "hey, how do you make a fixed len string in VB6?"
As the computer geek that I am, that the kind of questions I like to be able to answer.
These are important questions like all those questions from the 80's rally:

The name of all the original thundercats...
The planet where Luck Skywalker went to learn with Yoda...
Which Star Trek character appear in ALL the episodes (yes it is Spock, Kirk is not in all of them)
Well, the thing is to define a fixed len string in VB6 you do something like:


Dim aString As String * 10

If you do something like:

aString = "Mau" ' aString ==> "Mau "

That's all

Fixed length strings are automatically filled with spaces to pad them to their fixed-length. How do you get rid of the extra spaces? Duh!!! with RTrim$ don't you remember

When a variable like aString is declared, it will be filled with Null characters until it is used.

And yes functions (RTrim$, LTrim$, and Mid$) will not trim Null characters, so be sure to assign it with an empty string "" immediately.


Ahh! and by the way when you translate that to .NET, .NET does not have a fixed len string so the easiest thing to do is use:
Microsoft.VisualBasic.Compatibility.VB6.FixedLengthString.

[C#]

using Microsoft.VisualBasic.Compatibility;
...

void foo()

{

VB6.FixedLengthString aString = VB6.FixedLengthString(10, "Mau");

}

 

Migration of VB6 POS

7. May 2007 08:46 by Mrojas in General  //  Tags: , , , , , ,   //   Comments (0)

POS (Point of Sale) software is everywhere. Whether you're at a Bar, at Denny's, Pizza Hut, BK or at the Duty Free. It is maybe one of the software's more commonly used. A POS system is generally simple. It manages a basic inventory, registers sales, and somethings manages credit card payments. Obviously there are far more complex POS systems. A lot of POS systems where programmed in VB6. But as you know VB6 language (and I'm not discussing the reasons here) is now a dead language. A lot of customers do not want to buy VB6 applications, even if they get the job done. So it's time to move on. This is the First of a series of posts around issues migrating VB6 POS applications. If you have any comments just send them now!

Workaround for OCX State Problem (VMRC Active X)

26. April 2007 04:31 by Csaborio in General  //  Tags: ,   //   Comments (0)

On a previous post I was having problems with the VMRC ActiveX control when creating an instance at runtime.  The problem boiled down in having an invalid OCX state exception thrown at me whenever I tried to access a property of the VMRC ActiveX control at runtime.

After researching for quite a while on the Internet, it struck me that if I just placed the VMRC ActiveX in a UserControl at Design time, and instantiated that UserControl instead of the ActiveX directly, things would work great.  I implemented this into the VMCA application and it worked perfectly fine.   You can see I managed to get VMRC connections to different machines in different tabs at runtime on this post.

Some people have asked where they can get a copy of the VMCA.  Unfortunately as of now, the application hasn't been thoroughly tested and is missing some functionality which I deem as basic.  Also, this is something I have been working on my spare time and lately I have been swamped with other projects.  Perhaps the best approach would be to take it to stable phase and then try and get it on CodePlex so that everyone can pitch in...we'll see how that goes.

For all things related to software migration, be sure to visit Artinsoft's website. For training in Visual Basic to C# migrations, Visual Basic to VB.Net, Virtualization, and 64-bit training check our training web page.

Virtual Machine Configuration Assistant

13. April 2007 06:07 by Csaborio in General  //  Tags: ,   //   Comments (0)

As I previously mentioned, I've had some chance of working on the application dubbed as the Virtual Machine Configuration Assistant in the last few days.   One of the most noticeable changes are the GUI.  This is the old GUI of the app:

ZZ6A980B2C

This is the revamped, improved version:

ZZ1AC07DEE

The application has undergone major revisions under the hood.  I have tried to separate tasks into different classes in order to gain modularity.  So far I have a VMManager, a VHDManager, a VMRCManager and so on.  Reading the code now makes a lot more sense than before.

This is the part in which most of the work has been lately done, the Disks tab:

ZZ33FBC3C2

From here, you can pretty much do anything related with VHDs.  After modifying some ISOs,  I have also managed to completely automate the defragmentation-precompaction-compaction phase required to reduce the size of VHDs.  Now I just leave the process running and when I arrive the next day, my VHDs are like 50% smaller.

I had not touched C# in a while, and all I can say is "Wow".  C# rocks, it is very intuitive and creating efficient GUIs is a bliss.  One can only wish that there was a 2.0 framework to run under OS X.

I have also fixed the problem with OCX stats at runtime - actually it was a workaround, not a fix.  Here is a video I made of some of the features of the application, which include:

  • VHD Attachment
  • VHD Creation
  • VM Creation
  • VMRC in tabs for each of the machines
*sigh*...It has been impossible to embed the video here, here is the youtube link.

In case the resolution of the movie above is too small, the avi can also be downloaded.

For all things related to software migration, be sure to visit Artinsoft's website. For training in Visual Basic to C# migrations, Visual Basic to VB.Net, Virtualization, and 64-bit training check our training web page.

Problems Creating a VMRC ActiveX Instance at RunTime

9. April 2007 06:40 by Csaborio in General  //  Tags: ,   //   Comments (0)

During the Virtualization labs, which are freely available to anyone interested in Virtualization, the Artinsoft trainers have had a chance to teach the Virtual Server COM API and its uses.  One of the attendees showcases the application that they build on his blog. I think the application in its finished state is a great start to create something functional, but it is in no way something that can be used for management right out of the box.  The reason for this is simple: we wanted simple in order to reduce the learning curve of the COM API. 

I have started to work on my spare time on a new version of the Virtual Machine Configuration Assistant (VMCA) which will be version 2.0 due to major UI overhaul it has had.   One of the cool things I wanted to do, was the ability to open VMRC connections within the app in tabs (gotta love tabs in everything!).  So here is the interface I have so far (click on the image for larger view, as it has info on what I am trying to accomplish):

ZZ5B4D2238

Sounds easy, huh?  Well, that is what I thought.  I have in my application the reference to the VMRC ActiveX control, the image that you see above depicts a VMRC instance placed on the form in Design Time.

When the user selects the VMRC option, I have the following code:

vmrcControl = new AxVMRCClientControl();
vmrcControl.ServerAddress = "vs02";
vmrcControl.Size = new System.Drawing.Size(985, 675);
//Add a New Tab
this.tabPage1 = new TabPage();
tabPage1.Text = VMCA.VirtualInstances.getVMInstance().Name;
//Add the VMRC Control
tabPage1.Controls.Add(vmrcControl);
vmrcControl.Location = new System.Drawing.Point(0, 0);
this.tbcVMRC.TabPages.Add(tabPage1);
vmrcControl.UserName = "Administrator"

The line in red below is where all hell breaks loose:

ZZ735D6EE2

The problems seems to be that at design time, the VS Designer creates and configures a resource that is used to keep track of the ActiveX instance's state.  At runtime, this resource does not exists and that is the reason why the ActiveX is an invalid state.  Not being the ActiveX hacker that I would like to be, I am baffled on this problem.

Have you ever suffered with a problem such as the one above?  I have looked for help at various locations without any luck.  Although not critical, this feature is something that would definitely rock.  Help me solve this problem and I will send you a couple of pure quality Costa Rican coffee wherever you may be (if you are in Costa Rica, I'll send you beer instead ;)

I have posted a project which repros the problem:

http://amd.streamload.com/artinsoft/Links/5B75335893

In order to repro, just debug the app, and from the menus select Remote Control...if you can somehow make it through without the invalid OCX state exception, you are right on the money.

UPDATE: In order to run the project above, you *need* to have the VMRC ActiveX control installed on your machine.  The following page will guide you with the necessary steps to complete this process: https://www.microsoft.com/resources/virtuallabs/installactivex-technet.aspx

For all things related to software migration, be sure to visit Artinsoft's website.  For training in Visual Basic to C# migrations, Visual Basic to VB.Net,  Virtualization, and 64-bit training check our training web page.

Something like sprintf in C# or VB.NET

31. July 2006 11:11 by Mrojas in General  //  Tags: , , ,   //   Comments (0)

Recently I was wondering how to format  an output string like I used in C or C++ where we had the infamous and powerful sprintf but I could not find a good refence until I found this page.

http://blog.stevex.net/index.php/string-formatting-in-csharp/ I think it will be very useful to print it and have it close as a good cheat code sheet.

 

More Color to your Traces!

29. May 2006 08:37 by Mrojas in General  //  Tags: , ,   //   Comments (0)

Most Visual Basic programmers are familiar with using Debug.Print to follow their code's execution. The .NET environment introduces Tracing falicities that allows you to send messages to files or the console.

However the console output could be improved by using colors to highlight certain events. 
I developed a simple ColorTraceListener that can be used either with the My.Application.Log object or the Trace.TraceXXX methods. 
I first thing to do is create a ClassLibrary. It will be called ColorTraceListener. Add a ColorTraceListener.cs File and fill it with the following code:
 

Imports System

Imports System.Diagnostics

Imports System.Globalization

Imports System.Text

Imports System.Runtime.InteropServices 

Public Class ColorTraceListener

    Inherits ConsoleTraceListener

    Public Sub New()

        MyBase.New()

    End Sub 

    Public Sub New(ByVal useErrorStream As Boolean)

        MyBase.New(useErrorStream)

    End Sub 

    Friend Function IsEnabled(ByVal opts As TraceOptions) As Boolean

        Return ((opts And Me.TraceOutputOptions) <> TraceOptions.None)

    End Function 
 
 

    False)> _

    Public Overrides Sub TraceData(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ByVal data As Object)

        If ((Me.Filter Is Nothing) OrElse Me.Filter.ShouldTrace(eventCache, source, eventType, id, Nothing, Nothing, Nothing, data)) Then

            Me.WriteHeader(source, eventType, id)

            Dim text1 As String = String.Empty

            If (Not data Is Nothing) Then

                text1 = data.ToString

            End If

            Me.WriteLine(text1)

            Me.WriteFooter(eventCache)

        End If

    End Sub 

    False)> _

    Public Overrides Sub TraceData(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ByVal ParamArray data As Object())

        If ((Me.Filter Is Nothing) OrElse Me.Filter.ShouldTrace(eventCache, source, eventType, id, Nothing, Nothing, Nothing, data)) Then

            Me.WriteHeader(source, eventType, id)

            Dim builder1 As New StringBuilder

            If (Not data Is Nothing) Then

                Dim num1 As Integer = 0

                Do While (num1 < data.Length)

                    If (num1 <> 0) Then

                        builder1.Append(", ")

                    End If

                    If (Not data(num1) Is Nothing) Then

                        builder1.Append(data(num1).ToString)

                    End If

                    num1 += 1

                Loop

            End If

            Me.WriteLine(builder1.ToString)

            Me.WriteFooter(eventCache)

        End If

    End Sub 
 

    False)> _

    Public Overrides Sub TraceEvent(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ByVal message As String)

        If ((Me.Filter Is Nothing) OrElse Me.Filter.ShouldTrace(eventCache, source, eventType, id, message, Nothing, Nothing, Nothing)) Then

            Me.WriteHeader(source, eventType, id)

            Me.WriteLine(message)

            Me.WriteFooter(eventCache)

        End If

    End Sub 
 

    False)> _

    Public Overrides Sub TraceEvent(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ByVal format As String, ByVal ParamArray args As Object())

        If ((Me.Filter Is Nothing) OrElse Me.Filter.ShouldTrace(eventCache, source, eventType, id, format, args, Nothing, Nothing)) Then

            Me.WriteHeader(source, eventType, id)

            If (Not args Is Nothing) Then

                Me.WriteLine(String.Format(CultureInfo.InvariantCulture, format, args))

            Else

                Me.WriteLine(format)

            End If

            Me.WriteFooter(eventCache)

        End If

    End Sub 
 
 
 
 

    Private Sub WriteFooter(ByVal eventCache As TraceEventCache)

        If (Not eventCache Is Nothing) Then

            Me.IndentLevel += 1

            If Me.IsEnabled(TraceOptions.ProcessId) Then

                Me.WriteLine(("ProcessId=" & eventCache.ProcessId))

            End If

            If Me.IsEnabled(TraceOptions.LogicalOperationStack) Then

                Me.Write("LogicalOperationStack=")

                Dim stack1 As Stack = eventCache.LogicalOperationStack

                Dim flag1 As Boolean = True

                Dim obj1 As Object

                For Each obj1 In stack1

                    If Not flag1 Then

                        Me.Write(", ")

                    Else

                        flag1 = False

                    End If

                    Me.Write(obj1.ToString)

                Next

                Me.WriteLine(String.Empty)

            End If

            If Me.IsEnabled(TraceOptions.ThreadId) Then

                Me.WriteLine(("ThreadId=" & eventCache.ThreadId))

            End If

            If Me.IsEnabled(TraceOptions.DateTime) Then

                Me.WriteLine(("DateTime=" & eventCache.DateTime.ToString("o", CultureInfo.InvariantCulture)))

            End If

            If Me.IsEnabled(TraceOptions.Timestamp) Then

                Me.WriteLine(("Timestamp=" & eventCache.Timestamp))

            End If

            If Me.IsEnabled(TraceOptions.Callstack) Then

                Me.WriteLine(("Callstack=" & eventCache.Callstack))

            End If

            Me.IndentLevel -= 1

        End If

    End Sub 

    Private Sub WriteHeader(ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer)

        Dim oldColor As ConsoleColor = Console.ForegroundColor

        Select Case eventType

            Case TraceEventType.Error

                Console.ForegroundColor = ConsoleColor.Red

            Case TraceEventType.Critical

                Console.ForegroundColor = ConsoleColor.Magenta

            Case TraceEventType.Information

                Console.ForegroundColor = ConsoleColor.White

                'Case TraceEventType.Resume

                'Case TraceEventType.Start

                'Case TraceEventType.Suspend

                'Case(TraceEventType.Transfer)

                'Case TraceEventType.Verbose

            Case TraceEventType.Warning

                Console.ForegroundColor = ConsoleColor.Yellow

        End Select

        Me.Write(String.Format(CultureInfo.InvariantCulture, "{0} {1}:", New Object() {source, eventType.ToString}))

        Console.ForegroundColor = oldColor

        Me.Write(String.Format(CultureInfo.InvariantCulture, " {0} : ", New Object() {id.ToString(CultureInfo.InvariantCulture)}))

    End Sub

End Class 

The methods that handle the headers in the TextWriteListener are private (WriteHeader and WriterFooter) so we need to override them. Reflector comes very handy in this cases. 

No to test it Create a Vb Console Application: 

Module Module1 

    Sub Main() 
 

        My.Application.Log.WriteEntry("Error!", TraceEventType.Error)

        My.Application.Log.WriteEntry("Warning", TraceEventType.Warning)

        My.Application.Log.WriteEntry("Info", TraceEventType.Information)

        My.Application.Log.WriteEntry("Info", TraceEventType.Critical) 

        Trace.TraceError("An Error Happened!")

        Trace.TraceInformation("Just letting you know!")

        Trace.TraceWarning("Watch the road ahead") 

    End Sub 

End Module 

And use a simple configuration file like the following: 

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

<configuration>

    <system.diagnostics>

      <trace autoflush="true">

        <listeners>

          <add name="ColorLog" />

        listeners>

      trace>

        <sources>

            This section defines the logging configuration for My.Application.Log -->

            <source name="DefaultSource" switchName="DefaultSwitch">

                <listeners>

                    <add name="ColorLog"/>

                listeners>

            source>

        sources>

        <switches>

            <add name="DefaultSwitch" value="Verbose" />

        switches>

       <sharedListeners>

          <add name="ColorLog" type="Mrojas.ColorTraceListener, ColorTraceListener" />

        sharedListeners>

    system.diagnostics>

configuration> 
 

Categories