New VB6 and ASP Assessment Tool

16. July 2009 05:16 by enassar in General  //  Tags:   //   Comments (0)

We’ve just released a new VB6 and ASP Assessment Tool, which analyzes Visual Basic 6.0 and ASP projects in order to obtain an inventory of the code, components and their relationships. It generates a group of HTML and Excel reports that can be used as the basis for further calculations related to the effort and cost of converting the application to Visual Basic .NET, C#, and ASP.NET. The tool is free to download, very simple to install and run, and you can use the results to obtain a quick ballpark for a turn-key project performed by ArtinSoft or find out how much will a license of our Visual Basic Upgrade Companion will cost  (use the number of code plus design lines in both cases).

CapsLock, NumLock in C# and VB.NET

10. July 2009 12:49 by Mrojas in General  //  Tags: , , , , ,   //   Comments (0)

I was looking for a “.net” way of detecting the CapsLock state, but almost all the references pointed to pinvoke code like:

<DllImport("user32.dll")> _
Public Shared Function GetKeyState(VirtKey As Integer) As Integer
End Sub

And I finally found two ways:

1) You can call methods from the System.Console class:

You can use the System.Console.CapsLock property and if you want the NumLock state use: System.Console.NumberLock

or

2) You can call make an instance of Microsoft.VisualBasic.Devices.Keyboard. (For this if you are in C# you need to add a reference to Microsoft.VisualBasic.dll)

For example:

Microsoft.VisualBasic.Devices.Keyboard key = new Microsoft.VisualBasic.Devices.Keyboard();

and use properties like:

key.CapsLock

key.NumLock

key.ScrollLock

key.ShiftKeyDown

key.CtrlKeyDown

key.AltKeyDown

Printing RichTextBox contents in C#

10. July 2009 05:54 by Mrojas in General  //  Tags: , , , ,   //   Comments (0)

This post discusses and provides the implementation of a helper class to add support
for printing the formatted contents of a richtextbox control.

The print model in .NET is a little different than one used in VB6.

For example see: http://support.microsoft.com/kb/146022

Public Sub PrintRTF(RTF As RichTextBox, LeftMarginWidth As Long, _
   TopMarginHeight, RightMarginWidth, BottomMarginHeight)
   Dim LeftOffset As Long, TopOffset As Long
   Dim LeftMargin As Long, TopMargin As Long
   Dim RightMargin As Long, BottomMargin As Long
   Dim fr As FormatRange
   Dim rcDrawTo As Rect
   Dim rcPage As Rect
   Dim TextLength As Long
   Dim NextCharPosition As Long
   Dim r As Long

   ' Start a print job to get a valid Printer.hDC
   Printer.Print Space(1)
   Printer.ScaleMode = vbTwips

   ' Get the offsett to the printable area on the page in twips
   LeftOffset = Printer.ScaleX(GetDeviceCaps(Printer.hdc, _
      PHYSICALOFFSETX), vbPixels, vbTwips)
   TopOffset = Printer.ScaleY(GetDeviceCaps(Printer.hdc, _
      PHYSICALOFFSETY), vbPixels, vbTwips)

   ' Calculate the Left, Top, Right, and Bottom margins
   LeftMargin = LeftMarginWidth - LeftOffset
   TopMargin = TopMarginHeight - TopOffset
   RightMargin = (Printer.Width - RightMarginWidth) - LeftOffset
   BottomMargin = (Printer.Height - BottomMarginHeight) - TopOffset

   ' Set printable area rect
   rcPage.Left = 0
   rcPage.Top = 0
   rcPage.Right = Printer.ScaleWidth
   rcPage.Bottom = Printer.ScaleHeight

   ' Set rect in which to print (relative to printable area)
   rcDrawTo.Left = LeftMargin
   rcDrawTo.Top = TopMargin
   rcDrawTo.Right = RightMargin
   rcDrawTo.Bottom = BottomMargin

   ' Set up the print instructions
   fr.hdc = Printer.hdc   ' Use the same DC for measuring and rendering
   fr.hdcTarget = Printer.hdc  ' Point at printer hDC
   fr.rc = rcDrawTo            ' Indicate the area on page to draw to
   fr.rcPage = rcPage          ' Indicate entire size of page
   fr.chrg.cpMin = 0           ' Indicate start of text through
   fr.chrg.cpMax = -1          ' end of the text

   ' Get length of text in RTF
   TextLength = Len(RTF.Text)

   ' Loop printing each page until done
   Do
      ' Print the page by sending EM_FORMATRANGE message
      NextCharPosition = SendMessage(RTF.hWnd, EM_FORMATRANGE, True, fr)
      If NextCharPosition >= TextLength Then Exit Do  'If done then exit
      fr.chrg.cpMin = NextCharPosition ' Starting position for next page
      Printer.NewPage                  ' Move on to next page
      Printer.Print Space(1) ' Re-initialize hDC
      fr.hdc = Printer.hdc
      fr.hdcTarget = Printer.hdc
   Loop

   ' Commit the print job
   Printer.EndDoc

   ' Allow the RTF to free up memory
   r = SendMessage(RTF.hWnd, EM_FORMATRANGE, False, ByVal CLng(0))
End Sub

The VBCompanion provides excellent helpers that provide a lot fo the VB6 Printer object functionality, so you dont have to change any of your actual code, but in some cases, you might just want to remove that code, specially for very specific things like printing a RichTextBox.

So here I’m providing a .NET simplified helper that allows you to print the contents of a RichTextBox control. This helper is just based on the code published by Martin Muller in http://msdn.microsoft.com/en-us/library/ms996492.aspx. It provides an extension method for VS 2008 user so all you have to do is call RichTextBox.Print.

The implementation is simple. The RichTextBoxPrintHelper creates or receives an instance of a PrintDocument object, and event handlers are added to it for the BeginPrint, PrintPage and EndPrint events.

    private int m_nFirstCharOnPage;

    private void printDocument_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
    {
        // Start at the beginning of the text
        m_nFirstCharOnPage = 0;
    }

    private void printDocument_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
    {
        // To print the boundaries of the current page margins
        // uncomment the next line:
        //e.Graphics.DrawRectangle(System.Drawing.Pens.Blue, e.MarginBounds);

        // make the RichTextBoxEx calculate and render as much text as will
        // fit on the page and remember the last character printed for the
        // beginning of the next page
        m_nFirstCharOnPage = FormatRange(false,
            e,
            m_nFirstCharOnPage,
            control.TextLength);

        // check if there are more pages to print
        if (m_nFirstCharOnPage < control.TextLength)
            e.HasMorePages = true;
        else
            e.HasMorePages = false;
    }

    private void printDocument_EndPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
    {
        // Clean up cached information
        FormatRangeDone();
    }
The FormatRange method is called. This method will use the fill out some structures 
with page information and use the RichTextBox handle to send messages that will render
the control contents to the Printer’s HDC.
 
 /// <summary>
    /// Calculate or render the contents of our RichTextBox for printing
    /// </summary>
    /// <param name="measureOnly">If true, only the calculation is performed,
    /// otherwise the text is rendered as well</param>
    /// <param name="e">The PrintPageEventArgs object from the
    /// PrintPage event</param>
    /// <param name="charFrom">Index of first character to be printed</param>
    /// <param name="charTo">Index of last character to be printed</param>
    /// <returns>(Index of last character that fitted on the
    /// page) + 1</returns>
    public int FormatRange(bool measureOnly, PrintPageEventArgs e,
        int charFrom, int charTo)
    {
        // Specify which characters to print
        STRUCT_CHARRANGE cr;
        cr.cpMin = charFrom;
        cr.cpMax = charTo;

        // Specify the area inside page margins
        STRUCT_RECT rc;
        rc.top = HundredthInchToTwips(e.MarginBounds.Top);
        rc.bottom = HundredthInchToTwips(e.MarginBounds.Bottom);
        rc.left = HundredthInchToTwips(e.MarginBounds.Left);
        rc.right = HundredthInchToTwips(e.MarginBounds.Right);

        // Specify the page area
        STRUCT_RECT rcPage;
        rcPage.top = HundredthInchToTwips(e.PageBounds.Top);
        rcPage.bottom = HundredthInchToTwips(e.PageBounds.Bottom);
        rcPage.left = HundredthInchToTwips(e.PageBounds.Left);
        rcPage.right = HundredthInchToTwips(e.PageBounds.Right);

        // Get device context of output device
        IntPtr hdc = e.Graphics.GetHdc();

        // Fill in the FORMATRANGE struct
        STRUCT_FORMATRANGE fr;
        fr.chrg = cr;
        fr.hdc = hdc;
        fr.hdcTarget = hdc;
        fr.rc = rc;
        fr.rcPage = rcPage;

        // Non-Zero wParam means render, Zero means measure
        Int32 wParam = (measureOnly ? 0 : 1);

        // Allocate memory for the FORMATRANGE struct and
        // copy the contents of our struct to this memory
        IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fr));
        Marshal.StructureToPtr(fr, lParam, false);

        // Send the actual Win32 message
        int res = SendMessage(control.Handle, EM_FORMATRANGE, wParam, lParam);

        // Free allocated memory
        Marshal.FreeCoTaskMem(lParam);

        // and release the device context
        e.Graphics.ReleaseHdc(hdc);

        return res;
    }
 

Using the RichTextBox is even more simple. You add a richtextbox to a form and call the Print method:

image

        private void printToolStripMenuItem_Click(object sender, EventArgs e)
        {
            richTextBox1.Print();
        }

I’m attaching the source code for the helper an this sample application so you can use this.

DOWNLOAD SOURCE CODE

Prepare your VB6 Code for an Upgrade

9. July 2009 11:38 by Jaguilar in General  //  Tags: ,   //   Comments (0)

When either testing the trial version of the VBUC or actually running the migration tool on your project, there are a few things that you should check to ensure the best possible conversion. These are:

  • Project root: Make sure all projects are stored under a one “root” common directory. The VBUC migrates all Visual Basic 6.0 projects (*.vbp) found in a directory structure, including subdirectories, from one common root. You can read more information about setting up the folder structure in the VBUC Quick Start Guide.
  • Third-party Components: The VBUC requires that all third party components are correctly registered. Also, very important, ensure you correctly install all licenses for the components. Not including these licenses will not allow the VBUC to load and identify the PMEs (Properties, Methods and Events) and correctly either apply the necessary maps or generate the corresponding COM Interop wrappers.
  • Compile all projects: Make sure all projects compile correctly and that all the references between the output (EXE/DLL/OCX) of a project and the referenced component in another project match up. This will allow the VBUC pick up the references automatically, reducing the amount of migration warnings and thus minimize the work required to set up the migration solution. The VBUC Quick Start Guide contains additional details on the importance of this step.

Website Updates: More Information, Get a Quick Ballpark, Download a Trial and Buy a License Online

29. June 2009 06:27 by Jaguilar in General  //  Tags: , ,   //   Comments (0)

In the last couple of months we’ve done several significant updates to the website that I think are worth commenting about. Here is a quick rundown of what has changed:

We hope you find this new information we published useful, and please add a comment to this post or send me a message with your thoughts on the new changes and if there’s anything you would like to see on our site.

How to determine if a binary file has a dependency on the VB6.0 runtime

24. June 2009 07:18 by Jaguilar in General  //  Tags: , , ,   //   Comments (0)

Here is a quick way to know if a binary file (*.exe, *.dll, *.ocx, …) has a dependency on the Visual Basic 6.0 Runtime. The trick is to use the Dependency Walker tool to see its dependencies. The dependency you are looking for is the Visual Basic 6.0 runtime library (msvbvm60.dll), and it appears on the tree if you are dealing with a VB6.0 binary:

 

 

If you are concerned about the VB6.0 runtime not being supported after Windows Server 2008 and Windows 7, this is a trick that can help you decide whether to keep a particular third party ActiveX component in your application through COM Interop after migrating to the .NET Framework or to start looking for a replacement in case the runtime is no longer available (and thus the component will no longer work).

Dependency Walker is a freeware tool that was included with Visual Studio 6.0, is included in the Windows Support Tools and can be downloaded from the Dependency Walker homepage.

If the VB6.0 Runtime is supported in Windows 7, why should I move to .NET?

22. June 2009 08:43 by Jaguilar in General  //  Tags:   //   Comments (0)

This past couple of week I’ve been contacted by a couple of developers concerned with Microsoft’s decision to stop supporting the Visual Basic 6.0 IDE, but to continue support for the Visual Basic runtime and some support libraries in Windows 7 and 2008. This made me think about revisiting the topic with new information and changes since February, when I wrote this post.

It is obvious that Microsoft has been trying to drop support for VB6.0 for a while now. They have extended it a couple of times, and they say they are committed to "make sure the IDE works" for the lifetime of Vista and Windows 2K8. But here is an important part of the support statement that is worth highlighting:

“VB6 runtime will ship and will be supported in Windows 7 for the lifetime of the OS.  Developers can think of the support story for Vista being the same as it is for Windows 7.  However there are no plans to include VB6 runtime in future versions of Windows beyond Windows 7.”

This means that the next version of Windows will very likely not include the VB6.0 runtime files. This has obvious implications if you have a  large application that will require several person-years of effort to migrate (or rewrite, if you decide to go that path). There are also some additional implications on the components you are using, since they may have a dependency on the VB6.0 runtime and thus may not work, even if the rest of you application is already in .NET and using these components through COM Interoperability. Just to be sure I’m not spreading unnecessary panic, Windows 7 is not even out yet, and it will be covered by Microsoft’s OS support policies, so you are good for at least the next five years. If you think the effort to move away from this platform will take longer than (or at least close to) this timeframe, make sure you start evaluation your options soon.

Another important thing to keep in mind is that the VB6.0 runtime files are 32-bit only. Starting with Windows Server 2008 R2, 32-bit mode (WOW64) is optional, and the next version of Windows Server (tentatively due in 2011-2012) will be 64-bit only. This affects both server-side components, ASP, and client-side applications running on the server through Terminal Services, Citrix, or any other remote access technology (though they may able to run using WOW64, albeit requiring an extra configuration step).

A big change since I wrote the last post is that now Windows 7 includes a complete XP virtual machine to run legacy apps, known as XP Mode. I already made a couple of posts on this, and basically, this seems to be a good intermediate steps to “buy some time” before companies move their applications to supported platforms.

As I recommended in the previous post, you should read the  "Support Statement for Visual Basic 6.0 on Windows Vista, Windows Server 2008 and Windows 7". Also, the Microsoft Product Lifecycle details the specific dates when support ended for VB6.0.

Show Migration Errors, Warnings and Issues (EWIs) on Visual Studio’s Task List

This is a very simple configuration option that can really help you speed up the process of reviewing all migration EWIs (Errors, Warnings and Issues) when working with migrated code. In Visual Studio, you can use the Task List panel to keep track of a list of items (tasks) you need to go through. This Task List can be configured to show migration EWIs, as shown in the following screenshot:

For this to work, in the Visual Studio IDE, select Tools->Options from the main menu. In the Options window, navigate to Environment->Task List. Here, you’ll need to add the four types of EWIs inserted by the VBUC, along with their priority:

  • UPGRADE_ISSUE: Issues appear when there is some migrated code that is very likely to cause a compilation error. My recommendation is that you add it with Normal priority
  • UPGRADE_NOTE: Notes are basically information messages. For example, if the VBUC detects dead code, it will comment it out and add an UPGRADE_NOTE comment to make sure the developer understand why it was removed. This can be added as Low priority, since they very rarely require manual intervention after the migration.
  • UPGRADE_TODO: Partially upgraded code. These EWIs should be added as high priority, since they indicate the developer needs to perform some additional work to complete the migration.
  • UPGRADE_WARNING: Warnings appear when there is a difference in behavior between the VB6 code and its .NET equivalent. The solution provided normally works, but there are some scenarios where additional manual intervention may be required (most likely from runtime errors). I normally add them to the Task List as Normal priority.

 

With this configuration, you can very easily and quickly browse through all the EWIs in a file, and determine which ones actually require you to perform some manual work, and which ones can be either removed because the line they are tagging will work, or if their verification will be deferred until functional testing takes place.

You can read more about VBUC’s Errors, Warnings and Issues here, and about Visual Studio’s Task List at this link.

ColdFusion 8 and JRockIt

15. June 2009 18:41 by Mrojas in General  //  Tags: , , , , , , ,   //   Comments (0)

JRockIt is an interesting Java Virtual Machine. I really admire the technology used in it. Well following Mike’s post about Memory Leaks in Coldfusion http://www.schierberl.com/cfblog/index.cfm/2006/10/12/ColdFusion_memoryLeak_profiler I was trying to configure the JRockit JVM to do some profiling on an important application.

But alas. Time just flies and things have change a lot since Mike wrote that post. So this is basically an update:

1) JRockit must be downloaded from: http://www.oracle.com/technology/software/products/jrockit/index.html You must accept the license and also have an OTN Account (this is a free process). Download the right version for your platform. I tried the x86 version on my 64 bit server and it didn;t work, so use the version that fits better to your platform. However there is no 64 bit client version of Memory Leak and all the other nice client tools. But dont worry. Download both version 64 and 32 bits versions. You will use the 64 version for your server and the 32 bit version for monitoring.

2) Stop coldfusion server

3) Modify the jvm.config file. In my case it was in: C:\ColdFusion8\runtime\bin\jvm.config

comment out old java.home and add a new line like:
java.home=C:/Program Files/Java/jrmc-3.1.0-1.6.0/jre

In the java.args setting, remove parameter –Xbatch (dont know why, it just didnt work)

add a parameter like:
-Xmanagement:ssl=false,authenticate=false,autodiscovery=true

*In my case I also had to disable security in C:\Program files\Java\jrmc-3.1.0-1.6.0\jre\management\management.properties with a line like:

com.sun.management.jmxremote.authenticate=false

4) Re start coldfusion

DDE in .NET

10. June 2009 04:51 by Mrojas in General  //  Tags: , , , , , ,   //   Comments (0)

Someone recently made me remind an old technology called DDE.

“Dynamic Data Exchange (DDE) is a technology for communication between multiple applications under Microsoft Windows or OS/2

 

“The primary function of DDE is to allow Windows applications to share data. For example, a cell in Microsoft Excel could be linked to a value in another application and when the value changed, it would be automatically updated in the Excel spreadsheet. The data communication was established by a simple, three-segment model. Each program was known to DDE by its "application" name. Each application could further organize information by groups known as "topic" and each topic could serve up individual pieces of data as an "item". For example, if a user wanted to pull a value from Microsoft Excel which was contained in a spreadsheet called "Sheet1" in the cell in the first row and first column, the application would be "Excel", the topic "Sheet1" and the item "r1c1".

Note: In DDE, the application, topic and item are not case-sensitive.”

 

So in VB6 you can have something like:

 

Private Sub Form_Load()
Text1.LinkMode = 0
Text1.LinkTopic = "Excel|Sheet1"
Text1.LinkItem = "R1C1"
Text1.LinkMode = 1
End Sub

 

 

How can you do that in .NET. Is it possible in C#? Well I started looking around and found several forums explaining about all the API calls and I was just about to write my own solution when I found NDDE. This project hosted in CodePlex “provides a convenient and easy way to integrate .NET applications with legacy applications that use Dynamic Data Exchange (DDE)” :)

 

So this is a  nice example of how to do the previous lines in C#:

        //This class provides the infraestructure for DDE comunication
        NDde.Client.DdeClient ddeClient_TextBox1 = null;

        private void Form1_Load(object sender, EventArgs e)
        {
            //I initialize the DDEClient object. Application is Excel and Topic is Sheet1. I'm using the 
            //the TextBox as the syncronization object
            ddeClient_TextBox1 = new NDde.Client.DdeClient("Excel", "Sheet1", textBox1);
            //Connect to the DDE Server
            ddeClient_TextBox1.Connect();
            //Start the Advise Loop
            ddeClient_TextBox1.StartAdvise("R1C1", 1, true, 60000);
            //Setup the Advise Method
            ddeClient_TextBox1.Advise += new EventHandler<NDde.Client.DdeAdviseEventArgs>(ddeClient_TextBox1_Advise);
            //Setup a method to Poke the Server for TextBox cahnges
            textBox1.TextChanged += new EventHandler(textBox1_TextChanged);

        }
        
        void textBox1_TextChanged(object sender, EventArgs e)
        {
            //Syncronous Poking the server
            ddeClient_TextBox1.Poke("R1C1", textBox1.Text + "\0", 4000);
        }

        const string DDE_postFix = "\r\n\0";
        void ddeClient_TextBox1_Advise(object sender, NDde.Client.DdeAdviseEventArgs e)
        {
            //Advise only if needed
            if (e.Text.Length >=DDE_postFix.Length && textBox1.Text + DDE_postFix != e.Text)
                textBox1.Text = e.Text.Substring(0,e.Text.Length-3);
        }
NOTE: Remember that you need to download NDDE and add a reference to this library

This is very good library, you can also set up a lot of Async calls to even improve performance. I have even thought of making an extender as the ToolTip control to add LinkTopic, LinkMode and LinkItem properties for Winforms controls or provide extensions methods to make all the syntax easier, but that is for a future post. Good Luck.

VB6 Migration of Property Pages

9. June 2009 08:36 by Mrojas in General  //  Tags: , , , , , , ,   //   Comments (0)

How can I migrate property pages? Well that is a common question when migrating VB6 Activex controls.

Property Pages where commonly used in VB6 to provide a mechanism for your user controls to edit values.

.NET provides even more mechanisms for editing your control properties.  You can provide an editor for each one of your component properties or you can provide a ComponentEditor for all the component, this is very similar to the VB6 concept.

In .NET the ComponentEditor can be actived in the designer selecting Properties from the context menu when you right click over the control.

This is from the MSDN documentation:

“A component editor is used to edit a component as a whole and can be used to implement a
user interface similar to that of the property pages. You associate a component editor with a
component by using the
EditorAttribute attribute.” From: ComponentEditor Class

The VBUC does not process out of the box, your PropertyPages, but I developed a tool that can be
used so the VBUC can help you migrate those property pages. This tool will modify your VB6 project,
and VB6 PropertyPages source code to make those VB6 PropertyPages look like VB6 UserControls.
This will allow  the VBUC migration tool to recover some of the VB6 PropertyPages code and appearance
and with some manual changes you can get your property pages to work again.

Use the following link to downlaod the tool: DOWNLOAD TOOL

So these are the steps to migrate a VB6 Project that has Property Pages with the VB6.

1) Make a backup copy of your source code.

2) Run the TOOL with your project file. For example if your project file is Project1.vbp then run the tool like this:

FixPropertyPages Project1.vbp

This will generate a new VB6 Project file called ModifiedProject1.vbp

3) Open the VBUC, and migrate the new project file ModifiedProject1.vbp

4) Open the migrated solution in Visual Studio.

5) All your property pages will be migrated to .NET UserControls. You might need to go thru some changes to make them completely functional. Remeber to add the [ToolboxItem(false)] to these property pages because they do not need to be visible in your toolbox.

6) Now, to associate those property pages with your UserControl do this:

6.1) Add a new code file to your migrated solution. We are going to create a ComponentEditor, that will hold all the pages and associate that to the migrated control. Lets say the control is named Control1 and the property pages are PropertyPage1 and PropertyPage2.
We will call the ComponentEditor ComponentEditorToAssociatePagesForMyControl.
In this ComponentEditor we will add an internal class for each PropertyPage. This class will inherit from ComponentEditorPage. We will call this internal classes Page1, and Page2. And we will associate those classes with the ComponentEditorToAssociatePagesForMyControl in the GetComponentEditorPages().
 

The resulting code will be like:

C#
using System.Windows.Forms.Design;
using WindowsFormsApplication1;
using System.Drawing;
using System.ComponentModel;
[ToolboxItem(false)] 
public class ComponentEditorToAssociatePagesForMyControl : WindowsFormsComponentEditor
{
    // Methods
    public override bool EditComponent(ITypeDescriptorContext context, object component)
    {
        return false;
    }

    class Page1 : ComponentEditorPage
    {
        // Methods
        public Page1()
        {
            PropertyPage1ForControl1 page1 = new PropertyPage1ForControl1();
            Size mysize = new Size(400, 250);
            this.Size = mysize;
            this.Text = "Page 1 for Control1";
            this.Controls.Add(page1);
        }
        protected override void LoadComponent() { }
        protected override void SaveComponent() { }
    }

    class Page2 : ComponentEditorPage
    {
        // Methods
        public Page2()
        {
            PropertyPage2ForControl1 page2 = new PropertyPage2ForControl1();
            Size mysize = new Size(400, 250);
            this.Size = mysize;
            this.Text = "Page 2 for Control1";
            this.Controls.Add(page2);
        }
        protected override void LoadComponent() { }
        protected override void SaveComponent() { }
    }

    protected override System.Type[] GetComponentEditorPages()
    {
        return new System.Type[] { typeof(Page1),typeof(Page2) };
    }

    protected override int GetInitialComponentEditorPageIndex()
    {
        return 0;
    }
}

VB.NET

<ToolboxItem(False)> _
Public Class ComponentEditorToAssociatePagesForMyControl
    Inherits WindowsFormsComponentEditor
    ' Methods
    Public Overrides Function EditComponent(ByVal context As ITypeDescriptorContext, ByVal component As Object) As Boolean
        Return False
    End Function

    Protected Overrides Function GetComponentEditorPages() As Type()
        Return New Type() { GetType(Page1), GetType(Page2) }
    End Function

    Protected Overrides Function GetInitialComponentEditorPageIndex() As Integer
        Return 0
    End Function


    ' Nested Types
    Private Class Page1
        Inherits ComponentEditorPage
        ' Methods
        Public Sub New()
            Dim page1 As New PropertyPage1ForControl1
            Dim mysize As New Size(400, 250)
            MyBase.Size = mysize
            Me.Text = "Page 1 for Control1"
            MyBase.Controls.Add(page1)
        End Sub

        Protected Overrides Sub LoadComponent()
        End Sub

        Protected Overrides Sub SaveComponent()
        End Sub

    End Class

    Private Class Page2
        Inherits ComponentEditorPage
        ' Methods
        Public Sub New()
            Dim page2 As New PropertyPage2ForControl1
            Dim mysize As New Size(400, 250)
            MyBase.Size = mysize
            Me.Text = "Page 2 for Control1"
            MyBase.Controls.Add(page2)
        End Sub

        Protected Overrides Sub LoadComponent()
        End Sub

        Protected Overrides Sub SaveComponent()
        End Sub

    End Class
End Class

 

7) After creating the ComponentEditor you must associate the component Editor to your new component editors. This can be done with something like:

C# 

[Editor(typeof(ComponentEditorToAssociatePagesForMyControl), typeof(ComponentEditor))]
public class Control1 : UserControl

VB.NET

<Editor(GetType(ComponentEditorToAssociatePagesForMyControl), GetType(ComponentEditor))> _
Public Class Control1
8)  Now to use this property pages, go to the designer screen and open the context menu and select properties. And editor with your properties pages will appear :)

9) You still need to write some code for saving the property values that is something you have to add to the LoadComponent and SaveComponent methods of the internal classes in your ComponentEditor (ComponentEditorToAssociatePagesForMyControl in our previous example).

I hope this helps to get your code faster in .NET. I'm attaching a C# sample if you want to try it out.

VB6 TabIndex and C#

5. June 2009 05:30 by Mrojas in General  //  Tags: , , , , ,   //   Comments (0)

Some time ago Jose Aguilar had blogged about the Interesting Behavior of TabIndex in Migrated Applications. As he explained at the time there are functional differences between the TabIndex behaviour in VB6

 

If you look at Figure1.

image

Figure 1. This image show a VB6 form, the TabIndex values and the way the form navigates when you press Tab.

If you migrate that form with the VBUC and activate the TabOrder option in View\TabOrder you will see something like:

image

As you can see by the 0.1 and 0.3 and 5.4 and 5.2 values. TabOrder in .NET is hierarquical. When you press tab you will navigate to the next control in the container, and when you get to the last in that container then you will switch to the next one in the following container. This is different from the VB6 world when you would have switched from 0.1 to 5.2.

How can we fix this without a lot of manual corrections. Well you can override the ProcessTabKey method to navigate controls following the tabIndex without taking into account the containers.

The code you will need to add is:

        /// <summary>
/// holds a list of controls for tab navigation
/// </summary>
List<Control> controls = new List<Control>();
/// <summary>
/// Populates the list used for tab navigation
/// </summary>
/// <param name="c">Control to use to populate list</param>
protected void BuildOrder(Control c)
{
if (c.TabStop)
controls.Add(c);
if (c.Controls.Count > 0)
{
foreach (Control child in c.Controls)
BuildOrder(child);
}
}
/// <summary>
/// Transversers all form controls to populate a list ordered by TabIndex
/// that will be used to follow tabindex ignoring containers
/// </summary>
protected void BuildOrder()
{
if (controls.Count == 0)
{

foreach (Control c in this.Controls)
{
BuildOrder(c);
}
controls.Sort(
delegate(Control c1, Control c2) { return c1.TabIndex.CompareTo(c2.TabIndex); });
}
}
/// <summary>
/// Overrides default tabIndex behaviour
/// </summary>
/// <param name="forward"></param>
/// <returns></returns>
protected override bool ProcessTabKey(bool forward)
{
BuildOrder();
if (ActiveControl != null)
{
int index = controls.IndexOf(ActiveControl);
if (index != -1)
{
if (forward)
controls[(index + 1) % controls.Count].Select();
else
controls[index==0?controls.Count-1:index-1].Select();

return true;
}

else
return false;
}
else
return base.ProcessTabKey(forward);
}

After adding this code just run your project and it will fix the tabIndex issues.

A Better Visual Studio!

3. June 2009 04:21 by Mrojas in General  //  Tags: , , ,   //   Comments (0)

Recently I discovered in MSDN a great addition, a must to for all C# developers. CodeRush Express.

This product was build by DevExpress and it just make it perfect your experience with Visual Studio.

 

For example finding symbols or files, tabbing between references, and more than 20 differente refactorings!!!!

Take at look at this new extension! It’s a absolutely a must.

Extended WebBrowser Control Series:And the WebBrowser keeps going…

Well recently Kingsley has point me to a lot of useful links to improve the ExtendedWebBrowser. However he found another detail. When in Javascript you do something like a:

window.open(‘url’,’window’,’width=200;height=300’);

Those width and height settings were not being considered in the new window. I researched for I while until I found this great link:

HOW TO: Get Width and Height from window.open() Inside a WebBrowser Host by Using Visual Basic .NET

So basicly I follow the sugested code and added logic in my EventSink class:

        public void WindowSetLeft(int Left)
        {
            ///Should I calculate any diff?
            _Browser.Parent.Left = Left;

        }

        public void WindowSetTop(int Top)
        {
            _Browser.Parent.Top = Top;

        }

        public void WindowSetWidth(int Width)
        {
            int diff = 0;
            diff = _Browser.Parent.Width - _Browser.Width;
            _Browser.Parent.Width = diff + Width;

        }
        public void WindowSetHeight(int Height)
        {
            int diff = 0;
            diff = _Browser.Parent.Height - _Browser.Height;
            _Browser.Parent.Height = diff + Height;

        }
So now when the window opens it takes the specified width, heigth, left and top.

As always

HERE IS THE UPDATED CODE

Extended WebBrowser Control Series: WebBrowser Control and window.Close()

I had previously posted an extended version of the WebBrowser Control. This code posted in Opening Popup in a NewWindow and NewWindow2 Events in the C# WebBrowserControl, dealt with some issues when you want to have a form with a WebBrowser and in the enclosed page you have a Javascript code like:

window.open(“ <some url to a page”)

But recently another problem arised. What if you have a Javascript snippet like:

window.close()

OMG!!! Why haven’t I thought about it. Well Kelder wrote me about this problem and he also sent me some of his\her research results:

Solution (Add WebBrowser as unmanaged code):  blogs.msdn.com/jpsanders/archive/2008/04/23/window-close-freezes-net-2-0-webbrowser-control-in-windows-form-application.aspx

Solution (Add WebBrowser using WM_NOTIFYPARENT override):blogs.msdn.com/jpsanders/archive/2007/05/25/how-to-close-the-form-hosting-the-webbrowser-control-when-scripting-calls-window-close-in-the-net-framework-version-2-0.aspx

http://blogs.msdn.com/jpsanders/archive/2007/05/25/how-to-close-the-form-hosting-the-webbrowser-control-when-scripting-calls-window-close-in-the-net-framework-version-2-0.aspx

Solution (Implementation not detailed): social.msdn.microsoft.com/forums/en-US/winforms/thread/1199c004-9eb2-400d-a118-6e06bca9f1f0/

Proposes changing pop-up links to WebBrowser navigate: dotnetninja.wordpress.com/2008/02/26/prevent-opening-new-window-from-webbrowser-control/Close

problem observed (no solution):www.codeproject.com/KB/cpp/ExtendedWebBrowser.aspx

It seams to me that the better solution is to use jpsanders solution, so I created an ExtendWebBrowser_v2 (the following is the modified fragment):

//Extend the WebBrowser control
public class ExtendedWebBrowser : WebBrowser
{
    
    // Define constants from winuser.h
    private const int WM_PARENTNOTIFY = 0x210;
    private const int WM_DESTROY = 2;
    
    AxHost.ConnectionPointCookie cookie;
    WebBrowserExtendedEvents events;

    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {
            case WM_PARENTNOTIFY:
             if (!DesignMode) 
             {
                if (m.WParam.ToInt32() == WM_DESTROY) 
                {
                    Message newMsg = new Message();
                    newMsg.Msg = WM_DESTROY;
                    // Tell whoever cares we are closing
                    Form parent = this.Parent as Form;
                    if (parent!=null)
                        parent.Close();
                }
             }
            DefWndProc(ref m);
            break;
          default:
            base.WndProc(ref m);
            break;
        }
    }

The problem that might arise with this solution is that the parent might not be a Form but an user control, etc. For a more general aproach I think I should send a WM_DESTROY directly to the parent, but for most cases it works. I’m attaching the code and a sample page called test0.htm. I hope this helps and rembember you can always donate to programming geeks jejejejeje just kidding

HERE IS THE CODE

List Jobs in Oracle

21. May 2009 06:41 by Mrojas in General  //  Tags: ,   //   Comments (0)

If you have created any schedule jobs or you just need to see what jobs are available in a server you use the dba_jobs table.

The following links provides more details about this view: http://www.praetoriate.com/data_dictionary/dd_dba_jobs.htm

Minimize pain when executing Visual Basic 6 migrations in a Migration Factory Model.

18. May 2009 07:06 by algomez in General  //  Tags: , ,   //   Comments (0)

More and more companies are deciding to migrate their portfolio of Visual Basic 6.0 applications using a Migration Factory Model where knowledge, tools, methodologies and resources are reused.  A successful Visual Basic 6.0 migration to .NET in a migration factory model can bring enormous benefits if executed correctly and a lot of pain if not.

For that reason, here is a list of factors that should be taken into account by your factory teams to minimize pains, risks and ensure success:

  • Use a proven methodology to do software migrations from VB6 to .NET. ArtinSoft can help you review and tune your migration methodology based on years of experience to help mitigate risks and execute cost-effective migrations.
  • Knowledge transfer – Every migration project is different but having a knowledge base of best practices, learnings and manual changes in place and updated with every project, will give you a great tool to successfully complete your projects. Within your migration methodology you need to make sure that your teams are constantly updating this repository, especially during the manual changes phase. Developers won’t have to spend time doing research, trial and error exercises or navigating in the internet since the solution will be in this repository.
  • VBUC customizations are a key part of a migration methodology in a factory model. These customizations will increase the automatic migration rate, minimize manual work on pending projects and ensure that effort, duration and financial goals will be achieved. The knowledge base created during the migration process is the best input for VBUC customizations. You need to ensure that knowledge is gathered and store in a repository at all times.
  • Reengineering versus functional equivalence – Integrating source code migration work with reengineering work will drastically increase the complexity of your migration project. Whenever possible, plan for a staged migration where you achieve functional equivalence first and then work on reengineering tasks.
  • For optimal migration factory team performance, communication is a key. Not always everything is documented so besides the knowledge base, you need to integrate the different teams to learn from each other.
  • Dependencies between projects may minimize the ability to migrate projects in parallel. During the detailed assessment phase you need to work o a migration plan where you clearly define the dependencies between the different projects in your portfolio. You usually do this by using the VBUC in assessment model, application surveys, priorization lists and interviews with application developers.
  • The migration factory requires migration experts especially at early stages of the process. Be aware of training your people in advanced to be productive at early and not middle stages of the migration process.

Changing Software in these Times of Crisis Article at El Financiero

17. May 2009 11:46 by Jaguilar in General  //  Tags: ,   //   Comments (0)

The business-oriented newspaper, El Financiero, just published an article talking about the advantages of performing a migration instead of a manual rewrite. The article talks about how Banamex (part of Citigroup) saved an estimated 80% of the cost when compared to rewriting their 125 applications, totaling over 5 million lines of code. It also talks about the advantages of being in .NET, including how it allows customers to rapidly respond to changes in market conditions.

You can read the original article in Spanish at the following link: Cambiar el software en estos tiempos de crisis or read the Google Translation in English. You can also check out the Banamex/Citigroup case study at the following link: Banamex - Citigroup turns to ArtinSoft to ensure compliance and business continuity through massive migration to C#.NET

Aberdeen Group recognizes ArtinSoft as a key player in the VB 6 migration industry

Aberdeen Group recently published a report titled “Migrating from VB6 to .NET: The challenge of Software Agility in a Volatile Economy”.

The report contains a good summary of the status quo with respect to Visual Basic 6 renewal efforts.  It is based on a survey of 130 organizations at the end of 2008. 

The Aberdeen report contains lots of advice for organizations that are faced with the challenge of upgrading their infrastructure, I think it is worth reading it.

ArtinSoft is very proud to have been recognized as a key player in the Visual Basic migration game along with a number of its outsourcing partners.  This shows once more how our 15 years trajectory in the migration business is our best letter of presentation.

In his summary of the report, Aberdeen analyst Michael Lock also shows how best in class companies have a much greater tendency to use automatic migration tools to support their porting efforts.  During these times of financial uncertainty is more important than ever to minimize the cost of evolving your infrastructure and automation is certainly a good way of doing so.  ArtinSoft approach to automatic migration is aimed at minimizing the cost of reaching functional equivalence while at the same time ensuring that all delivered code is completely .NET native and ready to be evolved to the next level by our customers.  ArtinSoft offers the best balance between cost speed and future insurance.  Jose Aguilar also analyzes some of the conclusions from Aberdeen in this blog post.

If you are deciding what’s your next move with VB6, you should certainly read the Aberdeen report and you should look at our Visual Basic Upgrade Companion 3.0 and our new technical resources site www.VBtoNET.com .

Best-in-Class Companies more likely to use Code Conversion or Automated Porting Tools

8. May 2009 05:51 by Jaguilar in General  //  Tags: ,   //   Comments (0)

Yesterday TechNewsWorld published an article called Planning a Migration Route From Visual Basic 6 to .Net, which discusses some aspects of a report by the Aberdeen Group. The article contains lots of valuable information for those of you considering moving your VB6.0 applications to .NET, by giving a very good idea on the best practices performed by the “Best-in-Class” organizations. I wanted to touch briefly on some of the points from the article, and how it matches our experience helping Fortune/Global 1000 companies upgrade their applications to the latest technology.

Something that is consistent with what we’ve seen is that 33% of the respondents from Best-in-Class and 15% of the “All Others” organizations engage a third party to assist with the migration. We at ArtinSoft, with our Consulting Services group, and along with our world-wide partners, have seen this as a growing trend, and have accumulated a vast a mount of experience that can be leveraged by these organizations to move away from legacy environments.

Also, as part of our migration methodology, we promote a controlled process that first brings your VB6.0 application up to Functional Equivalence in .NET, and then you can use this as a base to enhance an improve your investment. For many clients we also use the extensibility capabilities of the Visual Basic Upgrade Companion to prepare the source code for these enhancements by automating specific architectural modifications required by our customers. These modifications represent an enhancement in itself, and also leave the code ready for further changes by making sure it meets all the practices and coding standards of the organization. The Vertex Omiga and Supervisor Case Studies are a good example in this regard – and we’ve done other migrations with even more important customizations that, unfortunately, I can’t mention directly.

Finally, I want to quote the following text from near the end of the article:

“The research shows that Best-in-Class companies are six times more likely than all other companies to use code conversion or automated porting tools in order to help accelerate part of the migration process.”

You can read our case studies that show this is in fact the case, and we have helped many organizations save time and resources when performing migrations aided by using the Visual Basic Upgrade Companion.

Categories