Resizing Forms in C#

In the VB6 world it was very common to use “Resizer” OCXs that you just put on your forms and that they handle all the proportional resizing needed if you changed your form.

It was very simple and easy.

However when I started looking for something like that in .NET it was quite hard to find. So finally I got to ComponentSource and found some alternatives and I evaluated them:

 

Component Vendor Pricing URL
Component One Sizer For .NET Component ONE I think you have to buy the Component One Studio. That’s $800 ($1000 with more support)
and I think is one license per developer, runtime-free
http://www.componentone.com/SuperProducts/StudioWinForms/
.NET Forms Resize Softgroup 380$ per developer
from ComponentSource
if you buy directly from them you can get the component for 180$

Each copy is licensed on a per developer basis. A developer may use the license on multiple CPUs as long as they are not used concurrently nor used by another developer. Run-time royalty free.
http://www.soft-group.it/net/index.php?c=3a&id=11
Resize OCX/.NET Larcom and Young 95$-100$ per license

one license per developer, runtime-free
http://www.lyoung.com/

 

All of them seem to work. So it really up to your company preferences, budget and the level of support you desire. I haven't made tests like how it behaves if you have thirdparty components or activex ??? maybe I'll review that later.

Project not generating the TLB

13. February 2009 04:01 by Mrojas in General  //  Tags: , , , ,   //   Comments (0)

My good friend Jafet, was recently dealing with an interesting bug in Visual Studio.

He created a simple Visual Studio Project that had just an interface that he exposed thru COM. He’s intention was to compile the Class Library and use the TLB file in other projects, but after building the solution he found out that there was no TLB file generated.

After some tests he finally found out that Visual Studio does not generates a TLB if there are not classes in the Project. So your options are, add a dummy class to your project or invoke the TLB tool from the command line.

:)

Debug XBAP using WinForms Host

26. January 2009 06:13 by Mrojas in General  //  Tags: , , , , ,   //   Comments (0)

Recently I had to deal with targeting an XBAP application that had some Windows Forms controls.

The problem is that those controls can only be used in a trusted environment. If you try to debug an XBAP with some Windows Forms Controls you will get an exception like:

Message: Cannot create instance of 'Page1' defined in assembly 'XBAPWithWinForms, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Exception has been thrown by the target of an invocation.  Error in markup file 'Page1.xaml' Line 1 Position 7.

It took me a while to found a solution, and it was thru Scott Landford Blog that I found a way around.

In short what he recommends to do is:

Change your settings to:

Start Action->Start external program = %windir%system32\PresentationHost.exe

  In my case (and the case of most people that is: c:\windows\system32\PresentationHost.exe)


Start Options->Command line arguments = -debug "c:\projects\myproject\bin\debug\MyProject.xbap" -debugSecurityZoneUrl "http://localhost:2022"

Copy the value from the Start URL after the –debug argument

Very import for using WinForms components you must run in FULL TRUST

fullTrust

 

Here is some XBAP code using a WinForms WebBrowser. They designer does not like it a lot but it works:

XBAPWithWinforms.zip

Welcome back Basic!!

15. January 2009 05:15 by Mrojas in General  //  Tags: , , ,   //   Comments (0)

My first language ever was GW-Basic. I was a teenager doing in summer work at a company that made polls about hair products and things like that. At that time I didn’t had a computer. They were tooooo expensive.

And I found a manual for GW-Basic. I stole it, to make a copy, my boss found out and he fired me :(. But then I had the power!! jeje. With my cousin Esteban we started out first programs. And we got our first sale :) :) :). It was the typical POS software for a small video rental  company.

Ahhh, and that was just the beginning.

So, I really appreciate basic, with all its strengths and weaknesses. I do most of my development now in C#, I think due to my C++, java years, and know I am more used to its syntax, and I really prefer C#. But I consider Basic a real treasure.

Well recently while digging in the Microsoft Dev Labs I discovered SmallBasic. I was just browsing for some new stuff and I am glad to have found this jewel.

Artinsoft (the company I work for) is a company that has devoted a lot of time in the research of automatic software migration to other platforms.Not for nothing one of our flapship products is Visual Basic Upgrade Companion, so basic in any form is always a delight for me. (I will soon post a brief article about bringing VBScript back to life in VB.NET just wait and see)

Ok. Back to SmallBasic.

 

First of all. The interface is great!!!

image IDE

It has a cool intellisense guide and you can even extend it :)

 

And they even resurrected LOGO!

image

I just hope to write a cool Turtle Graphics routine soon!

:)

Use C++ in C#

19. December 2008 07:00 by Mrojas in General  //  Tags: , , , , , ,   //   Comments (0)

COM


The idea is to make a class or several classes available thru COM. Then the compiled dll or the TLB is used to generate and Interop Assembly and call the desired functions.

With this solution the current C++ code base line can be kept or might require just subtle changes. 

Calling a function thru com is involved in a lot of marshalling and can add an additional layer that is not really needed in the architecture of the solution.

Creating a Managed Wrapper with Managed C++

The idea with this scenario is to provide a class in Managed C++ that will be available in C#. This class is just a thin proxy that redirects calls to the Managed object. 

Let’s see the following example: 

If we have a couple of unmanaged classes like: 

class Shape {

public:

  Shape() {

    nshapes++;

  }

  virtual ~Shape() {

    nshapes--;

  };

  double  x, y;  

  void    move(double dx, double dy);

  virtual double area(void) = 0;

  virtual double perimeter(void) = 0;

  static  int nshapes;

}; 
 

class Circle : public Shape { 

private:

  double radius;

public:

  Circle(double r) : radius(r) { };

  virtual double area(void);

  virtual double perimeter(void);

}; 
 

The first thing we can try, to expose our classes to .NET it to set the setting for managed compilation: 

Es posible que tu navegador no permita visualizar esta imagen.Es posible que tu navegador no permita visualizar esta imagen. 

If your project compiles then you are just very close, and what you need is to add some managed classes to your C++ project to expose your native classes: 

Let’s see the Shape class: 

//We can use another namespace, to avoid name collition.

//In this way we can replicate the structure of our C++ classes. 

namespace exposedToNET

{

      //Shape is an abstract class so the better thing

    // to do is to generate an interface 

      public interface class Shape : IDisposable

      {

      public:  

            //public variables must be exposed as properties

            property double x

            {

                  double get();

                  void set(double value);

            }

            property double y

            {

                  double get();

                  void set(double value);

            }

            //method do not expose any problems

            void move(double dx, double dy);

            double area();

            double perimeter();

            //public static variables must

          //be exposed as static properties

          //However we might need to create a new class

          //for all public static variables and methods

          //because C# does not accept methods in an interface

            static property int nshapes;

      };

      //Static methods or variables of abstract class are added here

      public ref class Shape_Methods

      {

                        //public static variables must be exposed as static properties

      public:

            static property int nshapes

            {

                  int get()

                  {

                        return ::Shape::nshapes;

                  }

                  void set(int value)

                  {

                        ::Shape::nshapes = value;

                  }

            } 

      };

} 

And for the Circle class we will have something like this: 

namespace exposedToNET

{ 
 

      public ref class Circle : Shape

      {

      private:

            ::Circle* c;

      public:

            Circle(double radius)

            {

                  c = new ::Circle(radius);

            }

            ~Circle()

            {

                  delete c;

            }

            //public variables must be exposed as properties

            property double x

            {

                  virtual double get()

                  {

                        return c->x;

                  }

                  virtual void set(double value)

                  {

                        c->x = value;

                  }

            }

            property double y

            {

                  virtual double get()

                  {

                        return c->y;

                  }

                  virtual void set(double value)

                  {

                        c->y = value;

                  }

            }

            //method do not expose any problems

            virtual void move(double dx, double dy)

            {

                  return c->move(dx,dy);

            }

            virtual double area()

            {

                  return c->area();

            }

            virtual double perimeter()

            {

                  return c->perimeter();

            }

            //public static variables must be exposed as static properties

            static property int nshapes

            {

                  int get()

                  {

                        return ::Shape::nshapes;

                  }

                  void set(int value)

                  {

                        ::Shape::nshapes = value;

                  }

            } 
 

      }; 

}

DOWNLOAD EXAMPLE CODE

SWIG

 

SWIG is a software development tool that connects programs written in C and C++ with a variety of high-level programming languages.

This is a great tool used for several languages like Python, Perl, Ruby, Scheme, and even in different platforms.

The exposure mechanism used in this scheme is platform invoke, the issues here are similar to those of COM because there is some marshaling going on. This scheme might be more efficient than the COM one but I haven’t really test it to be completely sure that it is better. 

I have reviewed the SWIG code and it might also be possible to modify its code to generate wrappers using managed C++, but this is an interesting exercise that I have to leave for my readers. Sorry I just don’t have enough time. 

But how is SWIG used? 

In SWIG what you do is that you add a .i file to your project. This file provides directives for some code generation that specify exactly what you want to expose and how. 

This can very helpful if you just want to expose some methods. 

If you are lazy like me you can just add something like: 

/* File : example.i */

%module example 

%{

#include "example.h"  ß you put here includes with the definitions for your classes

%} 

/* Let's just grab the original header file here */

%include "example.h" ß add alse the include here 

And SWIG will add a file like example_wrap.cxx that you have to compile with the rest of your C++ code. 

It will also generate a set of C# classes that you use in your C# application, so it seams to your program that all the code is just C#.  

SWIG is a great tool and has been testing in a lot of platforms.

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

23. October 2008 03:41 by Mrojas in General  //  Tags: ,   //   Comments (0)

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

Scripting your applications in .NET Part 2

14. October 2008 03:10 by Mrojas in General  //  Tags: , , ,   //   Comments (0)

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

9. October 2008 04:10 by Mrojas in General  //  Tags: , , ,   //   Comments (0)

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#

2. October 2008 11:49 by Mrojas in General  //  Tags: , , ,   //   Comments (0)

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");
                
            }

        }
    }
}