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

Extended WebBrowser Control Series: Opening Popup in a NewWindow

In a previous post, i had published an “Extended Version” of the WebBrowser control
that gave you access to events like the NewWindow2.
This event that is not public in the common WebBrowser control allows you to intercept
the NewWindow event but gives you the posibility to setup the the ppDisp property witch sets
a pointer to the WebBrowser where the new window will be open.

So i setup a small example using this “ExtendedBrowser”.

I created a simple page (well really it was my wife, I know about transport-layer, C++, bits etc, but I never remember HTML syntax):

<html>
<body>
<H1> This is sample page to test opening a pop up in a new form </H1>
<input type="button" onclick="window.open('test0.htm')"/>
</body>
</html>

And created a simple form like in the following picture:

image

 

Instead of using a WebBrowser control i just used an ExtendedWebBrowser from my previous post.

And added code like:

        private void extendedWebBrowser1_NewWindow2(object sender, NewWindow2EventArgs e)
        {
            //Intercepting this event will allow us to create a new form in which
            //we will open the new webpage, to do that we must set the ppDisp property
            //of the NewWindow2EventArgs
            FormWithExtendedBrowser form1 = new FormWithExtendedBrowser();
            form1.Show();
            e.PPDisp = form1.extendedWebBrowser1.Application;
        }

When I run the code , it now opens the pop up in my form:

image

But test if for yourself! :) HERE IS THE CODE

VB6 Migrating MouseIcon Property

30. April 2009 13:17 by Mrojas in General  //  Tags:   //   Comments (0)

In VB6 you can have code like:

Private Sub Command1_Click()
    Dim x As StdPicture
    Set x = LoadPicture("C:\setup.ico")
    Me.MouseIcon = LoadPicture("C:\setup.ico")
    Me.MousePointer = ccCustom
End Sub

 

How can you migrate that to .NET??????

Well maybe with a helper like the following can help:

using System; 
using System.Windows.Forms; 
using VB6 = Microsoft.VisualBasic.Compatibility.VB6.Support;

namespace Project2
{
    internal partial class Form1
        : System.Windows.Forms.Form
        {
        
            private void  Command1_Click( Object eventSender,  EventArgs eventArgs)
            {
                System.Drawing.Image x;
                x = System.Drawing.Image.FromFile("C:\\setup.ico");
                this.Cursor = CursorHelper.CreateCursor(x);

        }
            [STAThread]
             static void  Main()
            {
                    Application.Run(new Form1());
            }
        }




  public class CursorHelper 
  {
      private struct IconInfo
      {
        public bool fIcon;
        public int xHotspot;
        public int yHotspot;
        public IntPtr hbmMask;
        public IntPtr hbmColor;
      }
  
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    static extern IntPtr CreateIconIndirect(ref IconInfo icon);

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    [return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
    static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);

    private static Cursor CreateCursor(System.Drawing.Bitmap bmp, int xHotSpot, int yHotSpot)
    {
        IconInfo tmp = new IconInfo();
        GetIconInfo(bmp.GetHicon(), ref tmp);
        tmp.xHotspot = xHotSpot;
        tmp.yHotspot = yHotSpot;
        tmp.fIcon = false;
        return new Cursor(CreateIconIndirect(ref tmp));
    }


    public static Cursor CreateCursor(object picture)
    {
      if (picture is System.Drawing.Bitmap)
          return CreateCursor(picture as System.Drawing.Bitmap, 3, 3);
      else 
      {
          System.Drawing.Image image = null;
          IntPtr iunknown = System.Runtime.InteropServices.Marshal.GetIUnknownForObject(picture);
          if (iunknown == IntPtr.Zero)
          {
              throw new Exception("Unsupported format");
          }
          else 
          {
              Guid guidIPicture = new Guid("7BF80980-BF32-101A-8BBB-00AA00300CAB");
              Guid guidIPictureDisp = new Guid("7BF80981-BF32-101A-8BBB-00AA00300CAB");
              IntPtr testIntPtr = IntPtr.Zero;
              if (System.Runtime.InteropServices.Marshal.QueryInterface(iunknown,ref guidIPicture,out testIntPtr)==0)
              {
                  image = Microsoft.VisualBasic.Compatibility.VB6.Support.IPictureToImage(picture);
              }
              else if (System.Runtime.InteropServices.Marshal.QueryInterface(iunknown,ref guidIPictureDisp,out testIntPtr)==0)
              {
                  image = Microsoft.VisualBasic.Compatibility.VB6.Support.IPictureDispToImage(picture);
              }
              if (image == null)
              {
                  throw new Exception("Unsupported format");
              }
              using (System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(image))
              {
                  return CreateCursor(bitmap, 3, 3);
              }
          };
           
          
      }

    }

  }

}

Get the Week Number in C#

30. April 2009 10:56 by Mrojas in General  //  Tags: , , ,   //   Comments (0)

Here is some examples of how to determine the WeekNumber of a given Date

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {

        object index = DateTime.Now;
        int res = 0;
        //0    First day of year
        res = System.Globalization.CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(
        Convert.ToDateTime(index), System.Globalization.CalendarWeekRule.FirstDay, System.Globalization.DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek);

        //1    (Default) First four day week from Sunday
        res = System.Globalization.CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(
        Convert.ToDateTime(index), System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Sunday);

        //2    First four day week from StartOfWeek
        res = System.Globalization.CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(
                Convert.ToDateTime(index), System.Globalization.CalendarWeekRule.FirstFourDayWeek, System.Globalization.DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek);

        //3    First full week from Sunday
        res = System.Globalization.CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(
                Convert.ToDateTime(index), System.Globalization.CalendarWeekRule.FirstFullWeek, DayOfWeek.Sunday);
        
        //4    First full week from StartOfWeek
        res = System.Globalization.CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(
                Convert.ToDateTime(index), System.Globalization.CalendarWeekRule.FirstFullWeek, System.Globalization.DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek);


        }
    }
}

VB6 AddressOf operator Migration

31. March 2009 09:14 by Mrojas in General  //  Tags:   //   Comments (0)

I was looking into ways to migrate something like the AddressOf operator in VB6. I read in some forums that I could use a delegate, but I hadn’t seen a code sample, so I started googling until I found this great post.

It provided a great example of how to pass a pointer to a function. I am attaching here the code so you can benefit from this too.

 

Remember to put the Working directory pointing to the output directory of the C DLL. In my case it is

image

The idea in general is like this:

/// <summary>
/// Simple callback function.
/// </summary>
/// <param name="a">Some integer parameter.</param>
public delegate void CBFUNC(int a);

/// <summary>
/// Demo of a simple callback.
/// </summary>
/// <param name="f">Function to call back to</param>
/// <param name="a">Parameter which will be returned through the callback</param>
[DllImport("c_test_lib.dll")]
public static extern void DoCallback(CBFUNC f, int a);

DOWNLOAD CODE

Bittable What????

As vb6 migration experts in our company we deal everyday with a lot of issues around Interop and serialization.

One important thing to note is the concept of “Bittable Types”. I’m not making up terms. Those terms actually exist. Just see this link in MSDN.

In a few words, a bittable type is a type that has the same representation in managed and unmanaged code.

Why in earth is that important at all?

Because if you are calling that great C++ DLL implemented some years ago that just works ok, you won’t be able to pass a NON-Bittable type because that DLL will expect a binary representation different from that in the .NET virtual machine.

This is also an issue in other scenarios like:

  • Serializing content to files
  • Sending messages through messaging mechanisms like named-pipes or sockets.

Well, we have just introduced the problem so now let’s think on a nice solution for this problem.

Well Bittable Types are:

The following types from the System namespace are blittable types:

 

So now let’s look at a couple of non-BITTABLE types

DateTime

To test this differences let’s make a small test in VB6 and write a Date value to a file:

 

Private Sub SaveDateToFile()
    Open "C:\test1.bin" For Binary Access Write As #1
    Dim d1 As Date
    d1 = "1/1/2009"
    Put #1, , d1
    Close #1
End Sub

Now let’s make a quick program in Vb.NET

 

Sub Main()
        Dim f As System.IO.FileStream = System.IO.File.Open("C:\test2.bin", IO.FileMode.Create, IO.FileAccess.Write)
        Dim fw As New System.IO.BinaryWriter(f)
        Dim d As Date
        d = Convert.ToDateTime("1/1/2009")
        Dim val As Long = d.ToBinary()
        fw.Write(val)
        fw.Close()
        Main2()
    End Sub

 

If we compare these files we will have:

image

So the values are obviously different. This is because VB6 Date are stores with the OLE Automation DateFormat

So let’s change the C# code for something like:

 

    Sub Main2()
        Dim f As System.IO.FileStream = System.IO.File.Open("C:\test3.bin", IO.FileMode.Create, IO.FileAccess.Write)
        Dim fw As New System.IO.BinaryWriter(f)
        Dim d As Date
        d = Convert.ToDateTime("1/1/2009")
        fw.Write(d.ToOADate())
        fw.Close()
    End Sub

And now when we compare the files we will have:

image

 

So to make your Date values compatible with VB6 format you must user the DateTime method .ToOADate. Now if you are calling a DLL that expects a Date value in the same format used by VB6 then you will have to do this:

 

        Dim d As Date
        d = Convert.ToDateTime("1/1/2009")
        Dim handle As System.Runtime.InteropServices.GCHandle = System.Runtime.InteropServices.GCHandle.Alloc(d.ToOADate(), Runtime.InteropServices.GCHandleType.Pinned)
        Dim memory_address As IntPtr = handle.AddrOfPinnedObject()
        Try
            APICall(memory_address)
        Finally
            d = DateTime.FromOADate(System.Runtime.InteropServices.Marshal.ReadInt64(memory_address))
            handle.Free()
        End Try  

 

String

Most of the time you wont have to deal with String marshalling because adding marshaling tags to your API call solves most of the problems, but if you arent that luckyly then you might do something like:

IntPtr ptrToStringVar = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(strVar);
try
{
   APICall(ptrToStringVar);
}
finally
{
strVar = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(ptrToStringVar);
System.Runtime.InteropServices.Marshal.FreeHGlobal(ptrToStringVar);
}

NOTE: if you have an API that might return an string with /0 characters you must call the API with System.Runtime.InteropServices.Marshal.PtrToStringAnsi(ptrToStringVar,size), if you do that the Framework will take in consideration the size bytes at the ptrToStringVar memory address.

 

Double and Singles

At least between VB6 and VB.NET the double and single types follows the same format. Well, at least, that is the result of my tests.

Try it yourself, the following shows a simple test for double variables:

VB6

Private Sub SaveDoubleToFile()
    Open "C:\test1.bin" For Binary Access Write As #1
    Dim d1 As Double
    d1 = 1.123
    Put #1, , d1
    Close #1
End Sub

Sub Main()
    SaveDoubleToFile
End Sub

 

.NET

Module Module1

    Sub Main()
        Dim f As System.IO.FileStream = System.IO.File.Open("C:\test2.bin", IO.FileMode.Create, IO.FileAccess.Write)
        Dim fw As New System.IO.BinaryWriter(f)
        Dim d As Double
        d = 1.123
        fw.Write(d)
        fw.Close()
    End Sub


End Module
 

So you could make an api call in those cases with something like:

Dim handle As System.Runtime.InteropServices.GCHandle = System.Runtime.InteropServices.GCHandle.Alloc(d, System.Runtime.InteropServices.GCHandleType.Pinned)
Dim ptr As System.IntPtr = handle.AddrOfPinnedObject()
Try
    APICall(ptr)
Finally
    handle.Free()
End Try

Change CreateObject during Migration

One of our clients wanted to change the CreateObject function migration for a function of their own. So they wanted all cases like:

Dim x As Object
Set x = CreateObject("Excel.Application")

 

To be migrated to something like:

Excel.Application x = (Excel.Application) Utils.MyCreateObject("Excel.Application", "");

Our migratio vb6migration tool provides a new cool feature called CustomMaps. This feature allows you to provide some simple but useful changes to the way things get migrated.

For this case follow these steps:

1. Open the Visual Basic Upgrade Companion.

2. In the Tools Menu choose:

image

3. Create a new CustomMaps File and an an entry like the following:

 

image

Notice the Source name is VBA.Interaction.CreateObject. To find out this name you can look in your VB6 IDE, right click on the CreateObject and select goto Definition.
image 
 
image 
and for the target name just put the implementation that you what, for example you can write a function like:
class Utils
        {
            public static object MyCreateObject(string className,params object[] ignoreRestParams)
            {
                return Activator.CreateInstance(Type.GetType(className));
            }
        }

and set the SourceName to Utils.MyCreateObject (or NameSpace.Utils.MyCreateObject to use the fully qualified name). You just need to set the New Reference Name column because we will not change the definition of the function.