• I passed the 70-305 exam at TechEd!

    I attended TechEd on the Gold Coast last week, and took advantage of a free offer by Pearson VUE to take a free certification exam. I studied really hard (figuring that even if I failed, then at least I had experienced an exam without it costing me anything).

    Well the study paid off, as I passed “Developing and Implementing Web Applications with Microsoft® Visual Basic® .NET and Microsoft® Visual Studio® .NET” with an excellent result - 962!

    I’m going to see if I can have a go at 70-310 before the end of the year, and maybe complete the MCAD or MCSD next year.

  • Securing SQL 2000 with IPsec and Group Policy

    Here are links to resources mentioned in my presentation to the Adelaide SQL Server User Group (18th August).

  • Getting the name of a Windows Control Panel Applet

    I’ve been working on a program that needs to enumerate all the Control Panel applets in Windows, and ideally get the proper display name (rather than the .cpl filename). You can do this for a specific applet by using the DllImport Attribute to access the CPlApplet function that every applet implements:

    <DllImport("timedate.cpl", CharSet:=CharSet.Unicode)> \_
    Private Function CPlApplet(ByVal hwnd As IntPtr, ByVal uMsg As Integer, ByVal lParam1 As Integer, ByVal lparam2 As IntPtr) As Integer
    End Function
    

    My problem is that I needed to call this function for all applets (including non-Microsoft ones). .NET allows you to do dynamic P/Invoke code, but the only post I found in Google was from someone who was unable to get it to work. After using ildasm.exe to study what IL was generated by the static version, I noticed that the once major difference was that the dynamic version lacked the “preservesig” statement. The way to add this in is to use a custom attribute - you can’t do it via a parameter for any of the methods. The final version in VB.NET is based on the sample code from http://www.thecodeproject.com/csharp/dynamicinvokedll.asp

    Imports System
    Imports System.Runtime.InteropServices
    Imports System.Threading
    Imports System.Reflection
    Imports System.Reflection.Emit
    Imports System.Runtime.CompilerServices
    
    Module Module1
      Public Function DynamicDllFunctionInvoke(ByVal DllPath As String, ByVal EntryPoint As String, ByVal message As Int32) As Object
      Dim returnType As Type = GetType(Int32)
      Dim parameterTypes As Type() = {GetType(IntPtr), GetType(Int32), GetType(Int32), GetType(IntPtr)}
      Dim parameterValues As Object() = {IntPtr.Zero, message, 0, IntPtr.Zero}
      Dim asmName As AssemblyName = New AssemblyName asmName.Name = "tempDll"
      Dim dynamicAsm As AssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave)
    
      Dim dynamicMod As ModuleBuilder = dynamicAsm.DefineDynamicModule("tempModule") ', "tempModule.dll", True)
      Dim dynamicMethod As MethodBuilder = dynamicMod.DefinePInvokeMethod(EntryPoint, DllPath, MethodAttributes.Static Or MethodAttributes.Public Or MethodAttributes.PinvokeImpl, CallingConventions.Standard, returnType, parameterTypes, CallingConvention.Winapi, CharSet.Auto)
      Dim myAttributeType As Type = GetType(MethodImplAttribute)
      Dim myConstructorInfo As ConstructorInfo = myAttributeType.GetConstructor(New Type(0) \_
      {GetType(MethodImplOptions)})
      Dim myAttributeBuilder As New CustomAttributeBuilder(myConstructorInfo, \_ New Object(0) {MethodImplOptions.PreserveSig}) dynamicMethod.SetCustomAttribute(myAttributeBuilder) dynamicMod.CreateGlobalFunctions()
      Dim mi As MethodInfo = dynamicMod.GetMethod(EntryPoint)
      Dim retval As Object = mi.Invoke(Nothing, parameterValues)
      Debug.WriteLine(retval)
      Return retval
      End Function
    
      Sub Main()
        DynamicDllFunctionInvoke("c:\\WINDOWS\\system32\\timedate.cpl", "CPlApplet", 1) DynamicDllFunctionInvoke("c:\\WINDOWS\\system32\\timedate.cpl", "CPlApplet", 2)
      End Sub
    End Module