Showing posts with label windows. Show all posts
Showing posts with label windows. Show all posts

Thursday, April 3, 2008

Formatting code for HTML

This being my first blog I didn't have any tricks in my bag for formatting code. After some Google searching I only found two projects that looked useful. The first being this project which wasn't language aware and couldn't do any syntax highlighting. The second more promising project was this one and fortunately he posted the C# source for his library. Only problem is that it didn't support F# or Python. I went ahead and added support for those two languages, created a front end for the thing and added support for user specified CSS documents. In addition to exposing most of the built-in functionality my app has a preview mode which will display the formatted code in an embedded IE pane. I've posted my version of the library here, and I've also made available a pre-compiled binary.

Monday, March 31, 2008

The no-frills guide to .Net COM interop

So there a couple of guides out there that already cover some aspects of this post, but none of them cover all of the topics and many of them are convoluted. When I publish something to COM I usually end up consuming it via a scripting language like Python, Perl or VBScript so this little howto will reflect what I have found to be best practices. So here is the no-frills guide to exposing a C# class to COM.

  • Create an interface
  • Create a class that inherits from the interface
  • Add GUIDs to both interface and class using the "Guid" attribute define in "System.Runtime.InteropServices". You can use the GUID generation tool found in the "Tools" menu of Visual Studio.
using System;
using System.Runtime.InteropServices;

namespace MyNamespace{

    [Guid("EFB47A26-D84F-4092-927D-232E92FB77E8")]
    public interface IMyComponent{
        [DispId(1)]
        void DoStuff();
    }

    [Guid("8F3DFCDB-45F7-461d-9B19-B140CD6F05FA")]
    public class MyComponent : IMyComponent{
        public void DoStuff() { }
    }
}

  • Add the interface type to the interface, you don't need to know all the details but you should probably use the Dispatch type if this component is being consumed by a dynamically typed language such as Python.
  • Add the DispId to each method exposed by the interface. Again this helps when being consumed by Python. A note of caution though, that once these values are set and you register the component they should not change. It's not the end of the world if they do, but you will cause headaches for yourself.
[Guid("EFB47A26-D84F-4092-927D-232E92FB77E8")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMyComponent {
    [DispId(1)]
    void DoStuff();
}
  • Add the ProgId attribute to the class, set the value to Namespace.ClassName. This is again one of those things that may not be necessary but helps when using Python, Perl etc...
  • Add the ClassInterface attribute to the class setting the value to "ClassInterfaceType.AutoDispatch"
  • Add the ComDefaultInterfaceAttribute setting the value to the type of your interface. Again, not neccessarily required but Python has all sorts of trouble generating the wrapper classes if it isn't present.
[ProgId("MyNamespace.MyComponent")]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
[ComDefaultInterfaceAttribute(typeof(IMyComponent))]
[Guid("8F3DFCDB-45F7-461d-9B19-B140CD6F05FA")]
public class MyComponent : IMyComponent {
  public void DoStuff() { }
}
You need to enable two options in Visual Studio for your project. Open the properties for your project, and go the the application tab. Click on the "Assembly Information" button, and enable the make COM visible option. On the build tab you will also need to enable the register for com interop option at the bottom. You will also need to sign your assembly; you can use a self generated key through the signing tab of your project's properties. Once compiled Visual Studio will auto-register the assembly with COM so that you can test the interface with a script or OLEView. You can use regasm or build a Wix project to have it installed permanently.
using System;
using System.Runtime.InteropServices;

namespace MyNamespace
{

    [Guid("EFB47A26-D84F-4092-927D-232E92FB77E8")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface IMyComponent{
        [DispId(1)]
        void DoStuff();
    }

    [ProgId("MyNamespace.MyComponent")]
    [ClassInterface(ClassInterfaceType.AutoDispatch)]
    [ComDefaultInterfaceAttribute(typeof(IMyComponent))]
    [Guid("8F3DFCDB-45F7-461d-9B19-B140CD6F05FA")]
    public class MyComponent : IMyComponent{
        public void DoStuff() { }
    }
}

Friday, March 28, 2008

Playing around in WMI with F#

Started playing around with WMI in F# in order to update DNS records. After several hours I finally got it working. I ran into some problems on the last line of the function below. Apparently function used with iter() must return "unit" which is the F# equivalent of null. My anonymous function was returning an obj, appending the "; ()" to the end of the function fixed the return type. "()" in F# is the notation for the unit type. The guys from F# hub said this could also be done by using "|> ignore".

let UpdateCNameDNSRecord(record:string, value:string) =
    let query = String.Format("SELECT * FROM MicrosoftDNS_CNAMEType WHERE OwnerName='{0}'", record) in
    let scope = (@"\\.\root\MicrosoftDNS") in //new ManagementScope
    let searcher = new ManagementObjectSearcher(scope, query) in
    if (not (value.EndsWith("."))) then
        let value = (value + ".") in
    
    let inputP = [|null; box(value)|] in 
    IEnumerable.iter(
        
            fun (x:ManagementObject) ->
                if (x.Item("PrimaryName").ToString() <> value) then
                   x.InvokeMethod("Modify", inputP) |> ignore
            
       ) (IEnumerable.untyped_to_typed(searcher.Get()));;

Wednesday, March 26, 2008

An example win32 service in F#

I needed a small single purpose TCP socket server for work, and I thought it might be an opportune time to try a new programming language. My choices were Scala, F# or Erlang. The target platform was a win2k box and I wanted to be able to register it as a service so F# was the obvious choice. In the code below I modified the echo server example from the MIT F# site to run as a service.

// This sample code is provided "as is" without warranty of any kind. 
// We disclaim all warranties, either express or implied, including the 
// warranties of merchantability and fitness for a particular purpose. 

#light
#r "System.ServiceProcess.dll";;
#r "System.Configuration.Install.dll";;


// Echo Server: opens a service on the localhost which bounces data straight back  

open System.Net
open System.Net.Sockets
open System.Threading
open System.ServiceProcess
open System.ComponentModel
open System.Configuration.Install
open Microsoft.FSharp.Compatibility.CompatArray

let spawn f = (new Thread(new ThreadStart(f))).Start()

type EchoServer = class
    inherit ServiceBase as base
    
    new() as this = {} then base.ServiceName <- "SimpleEchoService"
    
    override this.OnStart(args:string[]) = 
        spawn(this.listen)
            
    member this.listen() =
        let sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP) 
        sock.Bind(new IPEndPoint(IPAddress.Any, 5120))

        let backlog = 2 // number of incoming connections that can be queued for acceptance
        sock.Listen(backlog)

        let port = (sock.LocalEndPoint :?> IPEndPoint).Port 
        Printf.printf "server accepting on port %d...\n" port

        while (true) do
            let csock = sock.Accept() 
            Printf.printf "the server has accepted a client on port %d...\n" port;
            spawn(fun () -> 
                let total = ref 0 
                try 
                    let buf = Bytearray.create 64
                    let stream = new NetworkStream(csock) 
                    while true do
                        Printf.printf "server reading...\n";
                        let nread = stream.Read(buf,0,64) 
                        Printf.printf "server read %d...\n" nread;
                        stream.Write(buf,0,nread);
                        total := !total + nread;
                    done;
                with 
                    | :? Sockets.SocketException 
                    | :? System.IO.IOException -> 
                        Printf.printf "client gone: server read %d bytes from that client\n" !total;
                        flush stdout
            )
        done

end