ArtinSoft's Blogs

Software Migration Experts
Welcome to ArtinSoft's Blogs Sign in | Join | Help
in Search

Mauricio Rojas Blog

October 2008 - Posts

  • Pesky VB Migration details

    During migratio of a simple project, we found an interesting migration details.

    The solution has a project with two Forms. Form1 and Form2. Form1 has a command button and in the Click for that command button it performs a code like UnLoad Form2.

    Unload 

     

    But it could happen that Form2 has not been loaded but in VB6 it is not a problem. In .NET the code will be something like form2.Close() and it could cause problems.

    A possible fix is to add some flag that indicates if the form was instanciated and the call the event.

     

     

  • PGP in Java

    Recenlty following a post in an AS400 Java Group, someone asked about a method for signing and verifying a file with PGP.
    I though, "Damn, that seems like a very common thing, it shouldn't be that difficult", and started google'ing for it.
    I found as the poster said that the Bouncy Castle API can be used but it was not easy.

    Well so I learned a lot about PGP and the Bouncy Castle and thanks god, Tamas Perlaky posted a great sample that signs a file, so I didn't have to spend a lot of time trying to figure it out.

    I'm copying Tamas Post because, I had problems accesing the site so here is the post just as Tamas published it:

    "To build this you will need to obtain the following depenencies.  The Bouncy Castle versions may need to be different based on your JDK level.

      bcpg-jdk15-141.jar
      bcprov-jdk15-141.jar
      commons-cli-1.1.jar

    Then you can try something like:
      java net.tamas.bcpg.DecryptAndVerifyFile -d test2_secret.asc -p secret -v test1_pub.asc -i test.txt.asc -o verify.txt
    And expect to get a verify.txt that's the same as test.txt.  Maybe.
    Here’s the download: PgpDecryptAndVerify.zip"

    And this is the original link: http://www.tamas.net/Home/PGP_Samples.html

    Thanks a lot Tamas

  • VSS reset admin password

    I had to access an old VSS database and nobody remember any password or the admin password.

    The tool from this page http://not42.com/2005/06/16/visual-source-safe-admin-password-reset 

    This was a lifesaver!

  • Coldfusion and Memory Problems

    If you have heavy processes in Coldfusion a nice thing is to track them with the JVMSTAT tool.

    You can get the JVMStat tool from http://java.sun.com/performance/jvmstat/

     And this post shows some useful information of how to use the tool with Coldfusion

    http://www.petefreitag.com/item/141.cfm

     

    Posted Oct 20 2008, 10:59 AM by Mrojas with no comments
    Filed under:
  • Scripting your applications in .NET Part 2

    Just more details about scripting

    Using the MS Scripting Object

     

    The MS Scripting Object can be used in .NET applications. But it has several limitations.

    The main limitation it has is that all scripted objects must be exposed thru pure COM. The scripting object is a COM component that know nothing about .NET

     

    In general you could do something like the following to expose a component thru COM:

     
       [System.Runtime.InteropServices.ComVisible(true)]
        public partial class frmTestVBScript  : Form
        {
            //Rest of code
        }
     
    NOTE: you can use that code to do a simple exposure of the form to COM Interop. However to provide a full exposure of a graphical component like a form or user control you should use the Interop Form ToolKit from Microsoft http://msdn.microsoft.com/en-us/vbasic/bb419144.aspx
     

    To expose an object in COM. But most of the properties and methods in a System.Windows.Forms.Form class, use native types instead of COM types.

     

    As you could see in the Backcolor property example:

     
    public int MyBackColor
    {
                get { return System.Drawing.ColorTranslator.ToOle(this.BackColor); }
                set { this.BackColor = System.Drawing.ColorTranslator.FromOle(value); }
    }
       Issues:
    • The problem with properties such as those is that System.Drawing.Color is not COM exposable.
    • Your script will expect an object exposing COM-compatible properties.
    • Another problem with that is that there might be some name collision.
     

    Using Forms

     

    In general to use your scripts without a lot of modification to your scripts you should do something like this:

     
    • Your forms must mimic the interfaces exposed by VB6 forms. To do that you can use a tool like OLE2View and take a look at the interfaces in VB6.OLB
    • Using those interfaces create an interface in C#
    • Make your forms implement that interface.
    • If your customers have forms that they expose thru com then if those forms add new functionality do this:
      • Create a new interface, that extends the basic one you have and
     

    I’m attaching an application showing how to to this.

    Performing a CreateObject and Connecting to the Database

     

    The CreateObject command can still be used. To allow compatibility the .NET components must expose the same ProgIds that the used.

     

    ADODB can still be used, and probably RDO and ADO (these last two I haven’t tried a lot)

     

    So I tried a simple script like the following to illustrate this:

    Sub ConnectToDB
    'declare the variable that will hold new connection object
    Dim Connection 
    'create an ADO connection object
    Set Connection=CreateObject("ADODB.Connection")
    'declare the variable that will hold the connection string
    Dim ConnectionString 
    'define connection string, specify database driver and location of the database
    ConnectionString = "Driver={SQL Server};Server=MROJAS\SQLEXPRESS;Database=database1;TrustedConnection=YES"
    'open the connection to the database
    Connection.Open ConnectionString
    MsgBox "Success Connect. Now lets try to get data"
    'declare the variable that will hold our new object
    Dim Recordset   
    'create an ADO recordset object
    Set Recordset=CreateObject("ADODB.Recordset")
    'declare the variable that will hold the SQL statement
    Dim SQL    
    SQL="SELECT * FROM Employees"
    'Open the recordset object executing the SQL statement and return records
    Recordset.Open SQL, Connection
    'first of all determine whether there are any records
    If Recordset.EOF Then
        MsgBox "No records returned."
    Else
    'if there are records then loop through the fields
    Do While NOT Recordset.Eof   
     MsgBox Recordset("EmployeeName") & " -- " & Recordset("Salary")
      Recordset.MoveNext    
    Loop
    End If
    MsgBox "This is the END!"

    End Sub
     
     

    I tested this code with the sample application I’m attaching. Just paste the code, press Add Code, then type ConnectToDB and executeStatement

     

    I’m attaching an application showing how to do this. Look at extended form. Your users will have to make their forms extend the VBForm interface to expose their methods.

     

    Using Events

     

    Event handling has some issues.

    All events have to be renamed (at least this is my current experience, I have to investigate further, but the .NET support for COM Events does a binding with the class names I think there’s a workaround for this but I still have not the time to test it).

    In general you must create an interface with all events, rename then (in my sample I just renamed them to <Event>2) and then you can use this events.

    You must also add handlers for .NET events to raise the COM events.

     
         #region "Events"
    
            public delegate void Click2EventHandler();
            public delegate void DblClick2EventHandler();
            public delegate void GotFocus2EventHandler();
    
            public event Click2EventHandler    Click2;
            public event DblClick2EventHandler DblClick2;
            public event GotFocus2EventHandler GotFocus2;
    
            public void HookEvents()
            {
                this.Click += new EventHandler(SimpleForm_Click);
                this.DoubleClick += new EventHandler(SimpleForm_DoubleClick);
                this.GotFocus += new EventHandler(SimpleForm_GotFocus);
            }
    
            void SimpleForm_Click(object sender, EventArgs e)
            {
                if (this.Click2 != null)
                {
                    try
                    {
                        Click2();
                    }
                    catch { }
                }
            }
    
            void SimpleForm_DoubleClick(object sender, EventArgs e)
            {
                if (this.DblClick2 != null)
                {
                    try
                    {
                        DblClick2();
                    }
                    catch { }
                }
    
            }
    
    
            void SimpleForm_GotFocus(object sender, EventArgs e)
            {
                if (this.GotFocus2 != null)
                {
                    try
                    {
                        GotFocus2();
                    }
                    catch { }
                }
            }
    
    
    
            #endregion
     Alternative solutions

    Sadly there isn’t currently a nice solution for scripting in .NET.  Some people have done some work to implement something like VBScript in .NET (including myself as a personal project but not mature enough I would like your feedback there to know if you will be interesting in a managed version of VBScript)  but currently the most mature solution I have seen is Script.NET. This implementation is a true interpreter. http://www.codeplex.com/scriptdotnet Also microsoft is working in a DLR (Dynamic Languages Runtime, this is the runtime that I’m using for my pet project of VBScript)

     

    The problem with some of the other solutions is that they allow you to use a .NET language like CSharp or VB.NET or Jscript.NET and compile it. But the problem with that is that this process generates a new assembly that is then loaded in the running application domain of the .NET Virtual machine. Once an assembly is loaded it cannot be unloaded. So if you compile and load a lot of script you will consume your memory. There are some solutions for this memory consumption issues but they require other changes to your code.

     

    Using other alternatives (unless you used a .NET implementation of VBScript which currently there isn’t a mature one) will require updating all your user scripts. Most of the new scripts are variants of the Javascript language.

      Migration tools for VBScript

    No. There aren’t a lot of tools for this task. But you can use http://slingfive.com/pages/code/scriptConverter/

      Download the code from: http://blogs.artinsoft.net/public_img/ScriptingIssues.zip


     

  • ADODB RecordSet Save in C# ASP.NET

    I saw this with Francisco and this is one possible solution:

    ASP Source

    rs.Save Response, adPersistXML

    rs is an ADODB.RecordSet variable, and its result is being written to the ASP Response

    Wrong Migration

    rs.Save(Response <-- The ASP.NET Response is not COM, ADODB.Recordset is a COM object, ADODB.PersistFormatEnum.adPersistXML);  

     So we cannot write directly to the ASP.NET response. We need a COM Stream object

    Solution

    ADODB.Stream s = new ADODB.Stream();

    rs.Save(s, ADODB.PersistFormatEnum.adPersistXML);               

    Response.Write(s.ReadText(-1));

    In this example an ADODB.Stream object is created, data is written into it and the it is flushed to the ASP.NET response

  • OutOfProcess In C#

    In VB6 you could create an OutOfProcess instance to execute some actions. But there is not a direct equivalent for that. However you can run a class in an another application domain to produce a similar effect that can be helpful in a couple of scenarios.

    This example consists of two projects. One is a console application, and the other is a Class Library that holds a Class that we want to run like an "OutOfProcess" instance. In this scenario. The console application does not necessary know the type of the object before hand. This technique can be used for example for a Plugin or Addin implementation.

    Code for Console Application

    using System;
    using System.Text;
    using System.IO;
    using System.Reflection;
    
    namespace OutOfProcess
    {
        /// <summary>
        /// This example shows how to create an object in an
        /// OutOfProcess similar way.
        /// In VB6 you were able to create an ActiveX-EXE, so you could create
        /// objects that execute in their own process space.
        /// In some scenarios this can be achieved in .NET by creating 
        /// instances that run in their own
        /// 'ApplicationDomain'.
        /// This simple class shows how to do that.
        /// Disclaimer: This is a quick and dirty implementation.
        /// The idea is get some comments about it.
        /// </summary>
        class Program
        {
            delegate void ReportFunction(String message);
    
            class RemoteTextWriter : TextWriter
            {
                ReportFunction report;
                public RemoteTextWriter(ReportFunction report)
                {
                    this.report = report;
                }
                public override Encoding Encoding
                {
                    get
                    {
                        return new UnicodeEncoding(false, false);
                    }
                }
    
                public override void Flush()
                {
                    //Nothing to do here
                }
    
    
                public override void Write(char value)
                {
                    //ignore
                }
    
                public override void Write(string value)
                {
    
                    report(value);
                }
    
                public override void WriteLine(string value)
                {
    
                    report(value);
                }
    
                //This is very important. Specially if you have a long running process
                // Remoting has a concept called Lifetime Management.
                //This method makes your remoting objects Inmmortals
                public override object InitializeLifetimeService()
                {
                    return null;
                }
    
            }
    
            static void ReportOut(String message)
            {
                Console.WriteLine("[stdout] " + message);
            }
    
            static void ReportError(String message)
            {
                ConsoleColor oldColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("[stderr] " + message);
                Console.ForegroundColor = oldColor;
            }
    
            static void ExecuteAsOutOfProcess(String assemblyFilePath,String typeName)
            {
                RemoteTextWriter outWriter = new RemoteTextWriter(ReportOut);
                RemoteTextWriter errorWriter = new RemoteTextWriter(ReportError);
    
                //<-- This is my path, change it for your app
    
    
                //Type superProcessType = AspUpgradeAssembly.GetType("OutOfProcessClass.SuperProcess");
                AppDomain outofProcessDomain = 
                    AppDomain.CreateDomain("outofprocess_test1", 
                    AppDomain.CurrentDomain.Evidence, 
                    AppDomain.CurrentDomain.BaseDirectory, 
                    AppDomain.CurrentDomain.RelativeSearchPath, 
                    AppDomain.CurrentDomain.ShadowCopyFiles);
                //When the invoke member is called this event must return the assembly
    
                AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(outofProcessDomain_AssemblyResolve);
                Object outofProcessObject = 
                    outofProcessDomain.CreateInstanceFromAndUnwrap(
                    assemblyFilePath, typeName);
                assemblyPath = assemblyFilePath;
                outofProcessObject.
                    GetType().InvokeMember("SetOut", 
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, 
                    null, outofProcessObject, new object[] { outWriter });
                outofProcessObject.
                    GetType().InvokeMember("SetError", 
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, 
                    null, outofProcessObject, new object[] { errorWriter });
                outofProcessObject.
                    GetType().InvokeMember("Execute", 
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, 
                    null, outofProcessObject, null);
                Console.ReadLine();
    
            }
    
            static void Main(string[] args)
            {
                string testAssemblyPath = 
                    @"B:\OutOfProcess\OutOfProcess\OutOfProcessClasss\bin\Debug\OutOfProcessClasss.dll";
                ExecuteAsOutOfProcess(testAssemblyPath, "OutOfProcessClass.SuperProcess");
    
            }
    
            static String assemblyPath = "";
            static Assembly outofProcessDomain_AssemblyResolve(object sender, ResolveEventArgs args)
            {
    
                try
                {
                    //We must load it to have the metadata and do reflection
                    return Assembly.LoadFrom(assemblyPath);
                }
                catch
                {
                    return null;
                }
            }
    
        }
    
    
    }
    

     

    Code for OutOfProcess Class

     

     

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace OutOfProcessClass
    {
        public class SuperProcess : MarshalByRefObject
        {
            public void SetOut(System.IO.TextWriter newOut)
            {
                Console.SetOut(newOut);
            }
            public void SetError(System.IO.TextWriter newError)
            {
                Console.SetError(newError);
            }
    
            public void Execute()
            {
                for (int i = 1; i < 5000; i++)
                {
                    Console.WriteLine("running running running ");
                    if (i%100 == 0) Console.Error.Write("an error happened");
                    
                }
    
            }
        }
    }
    
Powered by Community Server (Non-Commercial Edition), by Telligent Systems