Category Archives: .net Framework

Returning data from an MVC method with a small cute ActionResult

Standard

image

In order return data from an MVC method, Microsoft provide a useful ActionResult object called JSONResult.  JSONResult exposes a convenient Data property that you can use to serialize an object to JSON.

Here’s how it can be used:

var res = new JsonResult();
res.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
res.Data = someObject;
return res;

Pretty easy to use.   Unfortunately there’s no matching XMLResult class if you want to return a scrap of XML instead.  In the MVCContrib project on codeplex there’s an XMLResult, but it’s event signature is slightly different.

I’ve modified this class to provide the same signature. 

Here’s the usage:

var res = new XmlResult();
res.Data = someObject;
return res;

Here’s the class:

using System.Web.Mvc;
using System.Xml.Serialization;

namespace Sample
{
    /// <summary>
    /// Action result that serializes the specified object into XML and outputs it to the response stream.
    /// </summary>
    public class XmlResult : ActionResult
    {
        private object _objectToSerialize;
        private XmlAttributeOverrides _xmlAttribueOverrides;

        /// <summary>
        /// Creates a new instance of the XmlResult class.
        /// </summary>
        /// <param name="objectToSerialize">The object to serialize to XML.</param>
        public XmlResult()
        {
      
        }

        /// <summary>
        /// Creates a new instance of the XmlResult class.
        /// </summary>
        /// <param name="objectToSerialize">The object to serialize to XML.</param>
        public XmlResult(object objectToSerialize)
        {
            _objectToSerialize = objectToSerialize;
        }

        /// <summary>
        /// Creates a new instance of the XMLResult class.
        /// </summary>
        /// <param name="objectToSerialize">The object to serialize to XML.</param>
        /// <param name="xmlAttributeOverrides"></param>
        public XmlResult(object objectToSerialize, XmlAttributeOverrides xmlAttributeOverrides)
        {
            _objectToSerialize = objectToSerialize;
            _xmlAttribueOverrides = xmlAttributeOverrides;
        }

        /// <summary>
        /// The object to be serialized to XML.
        /// </summary>
        public object Data
        {
            get
            { return _objectToSerialize; }
            set
            {
                _objectToSerialize = value;
            }
        }

        /// <summary>
        /// Serialises the object that was passed into the constructor to XML and writes the corresponding XML to the result stream.
        /// </summary>
        /// <param name="context">The controller context for the current request.</param>
        public override void ExecuteResult(ControllerContext context)
        {
            if (_objectToSerialize != null)
            {
                var xs = (_xmlAttribueOverrides == null) ?
                    new XmlSerializer(_objectToSerialize.GetType()) :
                    new XmlSerializer(_objectToSerialize.GetType(), _xmlAttribueOverrides);
                context.HttpContext.Response.ContentType = "text/xml";
                xs.Serialize(context.HttpContext.Response.Output, _objectToSerialize);
            }
        }
    }
}

Bringing a Windows Application to the Foreground using .net

Standard

image

It’s surprising that there’s very little information available about bringing another windows application to the foreground.

The SetForegroundWindow api call can be useful in this regard, but it can’t be used unless you know the windows handle of the main window of the application you’re activating.  If the application you’re activating has many child windows, simply using the “MainWindowHandle” property on the Process object is not enough.

The code fragment and sample will show how to find a process, enumerate it’s child windows, then send these the foreground.

 

BringAppToForeground(“notepad”)

………

using System.Diagnostics; 
using System.Runtime.InteropServices;

……….

[DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd); 
[DllImport("user32.dll")] 

public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter,

string windowClass, string windowTitle);

       
private void BringAppToForeground(string appName) 
{

           // Find Parent 
           IntPtr parenthWnd = GetProcessWindowHandle(appName); 
           if (parenthWnd == IntPtr.Zero) return; 
           
           // Get list of child windows 
           List<IntPtr> loChildWindows = GetChildWindowHandles(parenthWnd);

           // Bring Windows to Front 
           BringWindowsToFront(loChildWindows.Reverse<IntPtr>());

}

private static IntPtr GetProcessWindowHandle(string processName) 
{ 
           IntPtr parenthWnd = IntPtr.Zero; 
           foreach (Process loProcess in Process.GetProcessesByName(processName)) 
           { 
               parenthWnd = loProcess.MainWindowHandle; 
               if (parenthWnd != IntPtr.Zero) break; 
           } 
           return parenthWnd; 
}

private static void BringWindowsToFront(IEnumerable<IntPtr> windows) 
{ 
           // Go through each and bring to front 
           foreach (IntPtr fronthWnd in windows) 
           { 
               SetForegroundWindow(fronthWnd); 
           } 
}

private static List<IntPtr> GetChildWindowHandles(IntPtr parenthWnd) 
{ 
           IntPtr hWnd = IntPtr.Zero; 
           List<IntPtr> loChildWindows = new List<IntPtr>(); 
           do 
           { 
               hWnd = FindWindowEx(parenthWnd, hWnd, null, null); 
               if (hWnd == IntPtr.Zero) break; 
               loChildWindows.Add(hWnd); 
           } 
           while (hWnd != IntPtr.Zero); 
           return loChildWindows; 
} 


To understand how to use this in a winforms project, take a look at the sample project.

Download Sample Project

Optimising Winforms Dropdown list combos for touch

Standard

image

The optimisation of the iPhone and the iPad for touch has contributed to it’s success. 

One example of this kind of optimisation is “drop down combos”.  Rather than sticking with the traditional touch UI of a big combo with a fat scrollbar (that would mess up web pages), they do something completely different.  As shown above a neat “roller” control is shown which makes combos a pleasure to use.

On the iPad the experience is more like a traditional combo, but it is not the same.

In the creation of Windows 7 Tablet user interfaces I am sure our users would prefer this kind of experience.

In Winforms it turns out that it’s possible to improve the touch experience markedly using the “OwnerDrawVariable” style on comboboxes.

As you can see, when the combo box looks relatively normal, not taking up much screen real estate….

image

Yet when it’s clicked, the control becomes bigger, so the normal flick scrolling features of Windows 7 tablet can work better.

image

The following code sample is a class called TouchCombo that can be used to cause combos to take on the new style.  Here’s the code for the sample form:

Public Class Form1
    Private Sub mPopulate(ByVal combo As ComboBox)
        combo.Items.Add("Alpha")
        combo.Items.Add("Beta")
        combo.Items.Add("Gamma")
        combo.Items.Add("Delta")
        combo.Items.Add("Epsilon")
        combo.SelectedIndex = 0

    End Sub

    Private moTouchCombo As New TouchCombo
    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        mPopulate(ComboBox1)
        mPopulate(ComboBox2)
        moTouchCombo.Connect(ComboBox2)
    End Sub
End Class

 

Here’s the code for the TouchCombo class:

 

Public Class TouchCombo

    Public Sub Connect(ByVal combo As ComboBox)
        combo.DrawMode = DrawMode.OwnerDrawVariable
        combo.DropDownHeight = 200
        combo.DropDownWidth = combo.Width * 1.5
        AddHandler combo.MeasureItem, AddressOf mMeasureItem
        AddHandler combo.DrawItem, AddressOf mDrawItem
        AddHandler combo.DropDown, AddressOf mDropDown
        AddHandler combo.DropDownClosed, AddressOf mDropDownClosed
        AddHandler combo.Disposed, AddressOf mDisposed
    End Sub

    Private Sub mDrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs)

        Dim loCombo As ComboBox = sender

        Using loBrush = New System.Drawing.SolidBrush(e.ForeColor)

            ' Draw the normal Background
            e.DrawBackground()

            ' If it's not dropped down, make it look normal
            If Not loCombo.DroppedDown OrElse e.State = DrawItemState.ComboBoxEdit OrElse e.State = DrawItemState.Default Then
                e.Graphics.DrawString(loCombo.Items(e.Index), loCombo.Font, loBrush, e.Bounds.X, e.Bounds.Y)
            Else
                ' Otherwise draw it big
                Using loFont As New System.Drawing.Font("Arial", 15, FontStyle.Bold)
                    e.Graphics.DrawString(loCombo.Items(e.Index), loFont, loBrush, e.Bounds.X, e.Bounds.Y)
                End Using
            End If

            e.DrawFocusRectangle()

        End Using

    End Sub
    Private Sub mMeasureItem(ByVal sender As Object, ByVal e As System.Windows.Forms.MeasureItemEventArgs)
        e.ItemHeight = 35
    End Sub
    Private Sub mDropDown(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim loCombo As ComboBox = sender
        loCombo.ItemHeight = 35
    End Sub

    Private Sub mDropDownClosed(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim loCombo As ComboBox = sender
        loCombo.ItemHeight = 15
    End Sub

    Private Sub mDisposed(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim loCombo As ComboBox = sender
        RemoveHandler loCombo.MeasureItem, AddressOf mMeasureItem
        RemoveHandler loCombo.DrawItem, AddressOf mDrawItem
        RemoveHandler loCombo.DropDown, AddressOf mDropDown
        RemoveHandler loCombo.DropDownClosed, AddressOf mDropDownClosed
        RemoveHandler loCombo.Disposed, AddressOf mDisposed
    End Sub
End Class

 

Download the project.

Capturing a still image from a Webcam in .net

Standard

image 

What if you want to capture a single image from a webcam?  It turns out that this is quite straight forward to do using a couple of Win32 api calls to the avicap32.dll library.

I encapsulated these api calls in a simple class.

To write a file called “snapshot.jpg” out to the desktop from a single webcam, simply declare the class and call a the TakePicture method.

Dim loSnap As New WebcamSnap
loSnap.TakePicture(0)

The devices collection shows a list of all webcam devices on your machine so you can populate a combo with them.

Note: This example has no decent error handling, which I suspect will be needed in the “real world” of multiple devices.

Here’s the WebcamSnap class:

Option Explicit On
Imports System.IO
Imports System.Runtime.InteropServices
''' <summary>
''' This class takes a snapshot from any or all attached webcams
''' </summary>
''' <remarks></remarks>
Public Class WebcamSnap
    Const WM_CAP As Short = &H400S

    Const WM_CAP_DRIVER_CONNECT As Integer = WM_CAP + 10
    Const WM_CAP_DRIVER_DISCONNECT As Integer = WM_CAP + 11
    Const WM_CAP_EDIT_COPY As Integer = WM_CAP + 30
    Const WS_CHILD As Integer = &H40000000
    Const WS_VISIBLE As Integer = &H10000000
    Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
        (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, _
        <MarshalAs(UnmanagedType.AsAny)> ByVal lParam As Object) As Integer

    Declare Function capCreateCaptureWindowA Lib "avicap32.dll" _
        (ByVal lpszWindowName As String, ByVal dwStyle As Integer, _
        ByVal x As Integer, ByVal y As Integer, ByVal nWidth As Integer, _
        ByVal nHeight As Short, ByVal hWndParent As Integer, _
        ByVal nID As Integer) As Integer

    Declare Function capGetDriverDescriptionA Lib "avicap32.dll" (ByVal wDriver As Short, _
        ByVal lpszName As String, ByVal cbName As Integer, ByVal lpszVer As String, _
        ByVal cbVer As Integer) As Boolean

    Public Devices As New List(Of String)
    Public Height As Integer = 480
    Public Width As Integer = 640
    Public OutputPath As String = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
    Public FilenamePrefix As String = "snapshot"
    Public Sub New()
        mLoadDeviceList()
    End Sub
    Private Sub mLoadDeviceList()
        Dim lsName As String = Space(100)
        Dim lsVers As String = Space(100)
        Dim lbReturn As Boolean
        Dim x As Integer = 0

        Do
            '   Get Driver name and version
            lbReturn = capGetDriverDescriptionA(x, lsName, 100, lsVers, 100)

            ' If there was a device add device name to the list
            If lbReturn Then Devices.Add(lsName.Trim)
            x += 1
        Loop Until lbReturn = False
    End Sub
    Public Sub TakePicture()
        For i = 0 To Me.Devices.Count - 1
            Dim lsFilename As String = Path.Combine(OutputPath, Me.FilenamePrefix & i & ".jpg")
            TakePicture(i, lsFilename)
        Next
    End Sub
    Public Sub TakePicture(ByVal iDevice As Integer)
        Me.TakePicture(iDevice, Path.Combine(OutputPath, Me.FilenamePrefix & ".jpg"))
    End Sub
    Public Sub TakePicture(ByVal iDevice As Integer, ByVal filename As String)

        Dim lhHwnd As Integer ' Handle to preview window

        ' Create a form to play with
        Using loWindow As New System.Windows.Forms.Form

            ' Create capture window
            lhHwnd = capCreateCaptureWindowA(iDevice, WS_VISIBLE Or WS_CHILD, 0, 0, Me.Width, _
               Me.Height, loWindow.Handle.ToInt32, 0)

            ' Hook up the device
            SendMessage(lhHwnd, WM_CAP_DRIVER_CONNECT, iDevice, 0)
            ' Allow the webcam apeture to let enough light in
            For i = 1 To 10
                Application.DoEvents()
            Next

            ' Copy image to clipboard
            SendMessage(lhHwnd, WM_CAP_EDIT_COPY, 0, 0)

            ' Get image from clipboard and convert it to a bitmap
            Dim loData As IDataObject = Clipboard.GetDataObject()
            If loData.GetDataPresent(GetType(System.Drawing.Bitmap)) Then
                Using loBitmap As Image = CType(loData.GetData(GetType(System.Drawing.Bitmap)), Image)
                    loBitmap.Save(filename, Imaging.ImageFormat.Jpeg)
                End Using
            End If

            SendMessage(lhHwnd, WM_CAP_DRIVER_DISCONNECT, iDevice, 0)

        End Using

    End Sub

End Class

Links

I found the original code sample here:

http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_22482234.html

(Although I’ve seen it all over the web in various guises)

In hell with SSL and WCF

Standard

 image

A long time ago I decided that WCF was one of those things I wouldn’t try and learn about in preference to learning other things, such as Silverlight, MVC and how to cook cookies properly.  Now that decision has come back to haunt me.

It seemed simple.  A client server prototype using wsHttpBindings and WCF.  My initial Project’s configuration files worked well on my local development machine (http).

The time came to put this on the server using SSL (https).

Much of the documentation on the web says that the simplest way of doing this is to configure IIS (IIS6 in my case) to work with SSL, then copy it over.  Words cannot express how wrong this proved to be.

For future reference, rest assured you will need very different versions of these files for local development as opposed to a production server.

I’ve also learnt that WCF gives as good as it gets in the ongoing competition between software development technologies in providing weird and useless error messages that are no hope at all in solving problems.  (Although handy for doing google searches to find others as miserable as you are)

Before

image

My original (Visual Studio generated) client app.config file looked like this:

<system.serviceModel>
  <bindings>
    <wsHttpBinding>
      <binding name="WSHttpBinding_IClientConnect" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
          bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
          maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
          messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
          allowCookies="false">
        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
        <reliableSession ordered="true" inactivityTimeout="00:10:00"
            enabled="false" />
        <security mode="Message">
          <transport clientCredentialType="Windows" proxyCredentialType="None"
              realm="" />
          <message clientCredentialType="Windows" negotiateServiceCredential="true"
              algorithmSuite="Default" />
        </security>
      </binding>
    </wsHttpBinding>
  </bindings>
  <client>
    <endpoint address="http://localhost:10916/SecureClientDemoServer/ClientConnect.svc"
        binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IClientConnect"
        contract="ClientService.IClientConnect" name="WSHttpBinding_IClientConnect">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
  </client>
</system.serviceModel>

My server web.config file looked like this:

    <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
        <services>
   <service behaviorConfiguration="ServiceBehavior" name="ClientConnect">
    <endpoint address="" binding="wsHttpBinding" contract="IClientConnect">
     <identity>
      <dns value="localhost" />
     </identity>
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
   </service>
  </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="ServiceBehavior">
                    <!– To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment –>
                    <serviceMetadata httpGetEnabled="true"/>
                    <!– To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information –>
                    <serviceDebug includeExceptionDetailInFaults="false"/>
                </behavior>
            </serviceBehaviors>
        </behaviors>
    </system.serviceModel>

 

After

 image

app.config

<system.serviceModel>
   <bindings>
    <wsHttpBinding>
      <binding name="WSHttpBinding_IClientConnect" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
        <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
        <security mode="Transport">
          <transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
          <message clientCredentialType="None"  algorithmSuite="Default" negotiateServiceCredential="false" establishSecurityContext="false" /> 
        </security>
      </binding>
    </wsHttpBinding>
  </bindings>
  <client>
    <endpoint address=https://remoteserver/SecureClientDemo/ClientConnect.svc binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IClientConnect" contract="ClientService.IClientConnect" name="WSHttpBinding_IClientConnect">
    </endpoint>
  </client>
</system.serviceModel>

 

web.config

    <system.serviceModel>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
        <services>
            <service behaviorConfiguration="ServiceBehavior" name="ClientConnect">
                     <endpoint address=https://remoteserver/SecureClientDemo/ClientConnect.svc bindingConfiguration="HttpsBinding" binding="wsHttpBinding" contract="IClientConnect">
                </endpoint>
                <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"
                                 name="MexHttpsBindingEndpoint" 
                                 />
            </service>
        </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="ServiceBehavior">
                    <!– To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment –>
                    <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/>
                    <!– To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information –>
                    <serviceDebug includeExceptionDetailInFaults="false"/>
                </behavior>
            </serviceBehaviors>
        </behaviors>
           <bindings>
         <wsHttpBinding>
          <binding name="HttpsBinding">
            <security mode="Transport">
              <transport clientCredentialType="None"/>
            </security>
          </binding>
        </wsHttpBinding>
            </bindings>
    </system.serviceModel>

 

 

Conclusion

This article is intended to show on the web a working set of configuration parameters, so for the time being I don’t have time to go into and explanation I only half understand.  I hope people find this helpful.

 

Links

http://msdn.microsoft.com/en-us/library/ms729700.aspx

http://stackoverflow.com/questions/1521117/wcf-over-ssl-404-error

http://stackoverflow.com/questions/2435823/the-provided-uri-scheme-https-is-invalid-expected-http-parameter-name-via

http://msdn.microsoft.com/en-us/library/ff648840.aspx

Adding the User-Agent when calling a Web Service with WCF

Standard

 image

“Every computing problem can be solved with yet another layer of indirection”

One of the cool things about the original Visual Studio (Visual Studio.Net) was how easy it was to create and consume web services. 

Over time, this support has been replaced by the trendy WCF services and WCF Soapclient infrastructure.    These new “Service References” differ from the original “Web References” in that they completely abstract the communications layer.  So it isn’t really a web reference anymore is it?

Recently I had to create a client program that called a .net 1.1 asmx web service.  This web service accessed the HTTP-Header variable “User-Agent”.   The original web service client proxies (Web References) that were generated by Visual Studio used to supply a User-Agent.  This is no longer the case.

It appears that a bug has been logged on Microsoft Connect, but it seems unlikely this will be fixed.

Most remedies to the problem discuss using code like this:

Dim httpRequestMessage As New HttpRequestMessageProperty()
httpRequestMessage.Headers.Add(USER_AGENT_HTTP_HEADER, Me.m_userAgent) requestMessage.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage)

Sadly when you’re working with a generated Service Reference I could see no way of using this code.  I assume it’s intended for a lower layer than the one I was working with.

Fortunately Paul Morgado has posted some code that I manipulated to solve the problem.    This article shows how to create a “behaviour” which can be then added to the service reference instance.

Like this:

Dim loService As New MyServiceReferenceSoapClient()
loService.Endpoint.Behaviors.Add(New HttpUserAgentEndpointBehavior("SomeUserAgentString"))
loService.SomeWebMethod()

Here’s the code for the HttpUserAgentEndpointBehaviour:

Imports System.ServiceModel
Imports System.ServiceModel.Channels
Imports System.ServiceModel.Dispatcher
Imports System.ServiceModel.Description
Imports System.ComponentModel
Public Class HttpUserAgentMessageInspector

    Implements IClientMessageInspector
    Private Const USER_AGENT_HTTP_HEADER As String = "user-agent"

    Private m_userAgent As String

    Public Sub New(ByVal userAgent As String)
        Me.m_userAgent = userAgent
    End Sub

#Region "IClientMessageInspector Members"

    Public Sub AfterReceiveReply(ByRef reply As System.ServiceModel.Channels.Message, ByVal correlationState As Object) Implements IClientMessageInspector.AfterReceiveReply
    End Sub

    Public Function BeforeSendRequest(ByRef request As System.ServiceModel.Channels.Message, ByVal channel As System.ServiceModel.IClientChannel) As Object Implements IClientMessageInspector.BeforeSendRequest
        Dim httpRequestMessage As HttpRequestMessageProperty
        Dim httpRequestMessageObject As Object
        If request.Properties.TryGetValue(HttpRequestMessageProperty.Name, httpRequestMessageObject) Then
            httpRequestMessage = TryCast(httpRequestMessageObject, HttpRequestMessageProperty)
            If String.IsNullOrEmpty(httpRequestMessage.Headers(USER_AGENT_HTTP_HEADER)) Then
                httpRequestMessage.Headers(USER_AGENT_HTTP_HEADER) = Me.m_userAgent
            End If
        Else
            httpRequestMessage = New HttpRequestMessageProperty()
            httpRequestMessage.Headers.Add(USER_AGENT_HTTP_HEADER, Me.m_userAgent)
            request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage)
        End If
        Return Nothing
    End Function

#End Region
End Class
Public Class HttpUserAgentEndpointBehavior
    Implements IEndpointBehavior
    Private m_userAgent As String

    Public Sub New(ByVal userAgent As String)
        Me.m_userAgent = userAgent
    End Sub

#Region "IEndpointBehavior Members"

    Public Sub AddBindingParameters(ByVal endpoint As ServiceEndpoint, ByVal bindingParameters As System.ServiceModel.Channels.BindingParameterCollection) Implements IEndpointBehavior.AddBindingParameters
    End Sub

    Public Sub ApplyClientBehavior(ByVal endpoint As ServiceEndpoint, ByVal clientRuntime As System.ServiceModel.Dispatcher.ClientRuntime) Implements IEndpointBehavior.ApplyClientBehavior
        Dim inspector As New HttpUserAgentMessageInspector(Me.m_userAgent)
        clientRuntime.MessageInspectors.Add(inspector)
    End Sub

    Public Sub ApplyDispatchBehavior(ByVal endpoint As ServiceEndpoint, ByVal endpointDispatcher As System.ServiceModel.Dispatcher.EndpointDispatcher) Implements IEndpointBehavior.ApplyDispatchBehavior
    End Sub

    Public Sub Validate(ByVal endpoint As ServiceEndpoint) Implements IEndpointBehavior.Validate
    End Sub

#End Region
End Class

Getting the parent process in VB.Net

Standard

 

image

The .net framework’s Process object lacks a means of determining which process invoked it. 

There are 3 techniques I have seen for determining this:

  • Api Calls
  • Iterating through the process table
  • Using wmi

This code sample uses the 3rd technique.  

Usage:

The code exposes a new “Parent” process function on the standard System.Diagnostics.Process class.

MessageBox.Show(System.Diagnostics.Process.GetCurrentProcess.Parent.Id)

Source:

Imports System.Management
Public Module ProcessExtensions
    <System.Runtime.CompilerServices.Extension()> _
    Public Function Parent(ByVal process As Process) As Process
        Return process.GetProcessById(miGetParentProcessId(process.Id))
    End Function
    Private Function miGetParentProcessId(ByVal processId As Integer) As Integer

        Dim loQuery As SelectQuery = New SelectQuery(String.Format("select * from Win32_Process where ProcessId = {0}", processId))
        Dim loSearcher As ManagementObjectSearcher = New ManagementObjectSearcher(loQuery)
        Dim loProcesses As ManagementObjectCollection = loSearcher.Get()

        If loProcesses.Count > 0 Then
            Return loProcesses(0)("ParentProcessId")
        End If
        Return 0
    End Function
End Module

 

 

References

Kill a specific process – System.Management forum post

Retrieving the Parent Process of a Child when Multiple Instances Exist – Robert Villahermosa

System Management Select Query

Hosting Winforms in Firefox

Standard

 image

I have a strange fascination with hybrids.  Combining old and new technologies in bizarre and interesting ways.   Why must developers make “the choice” between a web or native technology? It would be great to build applications that would increase or decrease in features depending on the platform they were run on.

 

clip_image002

Do you have a Winforms application that you’d like to host in a web browser?  There’s an interesting technique you can use to do this enabled by .net Framework 3.5.

The .net framework provides the ability to create WPF web applications (commonly called XBAP).  WPF has the ability, in turn, to host Winforms. 

Security

It appears that in order to do this effectively, it’s necessary to deploy your XBAP application as a “Full Trust” application.

image

The code

To use this, create an XBAP project, then a page a “WinformHost” control on it.   The XAML could look like this:

<Page x:Class="Page1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Page1">
    <DockPanel LastChildFill="True">
        <Button Name="Button1"  DockPanel.Dock="Bottom"  >This is a WPF Button</Button>
        <WindowsFormsHost Name="WinformHost"   />
    </DockPanel>
</Page>

Then, create some code to instantiate your winform and show it on the Winform host:

Class Page1

    Private Sub Page1_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim loForm As New HelloWorldWinform

        WinformHost.Child = WinformToUserControl.GetWrapper(loForm)
        loForm.Show()

    End Sub
End Class

Here’s the subroutine:

Public NotInheritable Class WinformToUserControl

    Public Shared Function GetWrapper(ByVal form As System.Windows.Forms.Form) As System.Windows.Forms.Control
        Dim loPanel As New System.Windows.Forms.Panel
        loPanel.Dock = Forms.DockStyle.Fill
        ShowFormInControl(loPanel, form)
        Return loPanel
    End Function

    Private Shared Sub ShowFormInControl(ByVal ctl As System.Windows.Forms.Control, ByVal frm As System.Windows.Forms.Form)

        frm.TopLevel = False
        frm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
        frm.AutoScaleMode = Forms.AutoScaleMode.Dpi
        ctl.Controls.Add(frm)

        frm.Dock = Forms.DockStyle.Fill

    End Sub
End Class

   

Interesting bits and pieces

We found that in order for the items inside the control to scale properly, the AutoScaleMode property on the Winform must be set to Dpi instead of the default, which is Font.  I have a feeling this is because Dpi is the mode preferred for WPF, but I am uncertain.

In the sample WinformToUserControl class I found it better to contain the Winform inside a panel rather than exposing the Winform directly.  It seemed to make it more stable.  Feel free to experiment with taking it off.

Gotchas

As of time of writing, Firefox on my Windows 7 64 bit machine steadfastly refuses to run xbap.  It appears the “Windows Presentation Foundation” addin has not been automatically installed.  I have no idea how to install it.  There’ appears to be no information about how to do so.  So if you have it, good for you.  If you don’t….try re-installing the .net framework 3.51 (which didn’t work for me…)

I do know there was some controversy about this addin being temporarily blacklisted by Mozilla due to security concerns last month, but that’s all over now isn’t it?  

 

Download

You can download a sample project here.

image

Links

Enabling callto (Skype) in your application

Standard

image image

You may have noticed that Skype seems to embed itself into Internet Explorer, Firefox and Chrome.  It recognises contacts and phone numbers in the page and provides the ability to call them.

I believe people will expect this kind of functionality in conventional windows applications also.  To assist with this I created a little class that will not only allow calls, but allows a check for the existence of a skype and give the ability to extract the calling applications icon.

Sample Project

The sample winforms project includes the CallTo class and a simple Winforms test form:

image

The form has a textbox and button.   One load, the call button is enabled and give an image.  The button makes the call.

 

Public Class Form1

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim loCallTo As New CallTo
        cmdCall.Image = loCallTo.Image
        cmdCall.Enabled = loCallTo.Enabled
    End Sub
    Private Sub cmdCall_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdCall.Click
        Dim loCallTo As New CallTo
        loCallTo.DoCall(txtPhoneNumber.Text)
    End Sub

End Class

 

 

Heres the source of CallTo.vb:

 

Imports Microsoft.Win32
Imports System.Runtime
Imports System.Runtime.InteropServices

''' <summary>
''' This class allows for making callto calls
''' </summary>
Public Class CallTo

    ''' <summary>
    ''' Gets the image.
    ''' </summary>
    ''' <value>The image.</value>
    Public ReadOnly Property Image() As Image
        Get
            If Not Enabled Then Return Nothing

            Dim lsValue As String
            With Registry.ClassesRoot.OpenSubKey("callto\DefaultIcon")
                lsValue = .GetValue("")
            End With

            If lsValue.Contains(",") Then
                Dim lsBits() As String = lsValue.Split(","c)
                Dim lsFilename As String = lsBits(0).Trim(New Char() {""""c})
                Dim liPosition As Integer = Val(lsBits(1))
                Return moGetIconFromExeOrDll(lsFilename, liPosition)
            Else
                Return Nothing
            End If

        End Get
    End Property
    Private Declare Auto Function ExtractIcon Lib "shell32" ( _
ByVal hInstance As IntPtr, ByVal lpszExeFileName As String, _
ByVal nIconIndex As Integer) As IntPtr
    Private Function moGetIconFromExeOrDll(ByVal filename As String, ByVal position As Integer) As Image
        Dim hInstance As IntPtr = Marshal.GetHINSTANCE( _
           System.Reflection.Assembly.GetExecutingAssembly.GetModules()(0))
        Dim hIcon As IntPtr = ExtractIcon(hInstance, filename, position)
        Dim loBitmap As Bitmap = Bitmap.FromHicon(hIcon)
        Dim loReturn As Image = loBitmap.GetThumbnailImage(16, 16, Nothing, Nothing)

        loBitmap.Dispose()
        Return loReturn

    End Function

    ''' <summary>
    ''' Gets a value indicating whether this CallTo is enabled.
    ''' </summar
    ''' <value><c>true</c> if enabled; otherwise, <c>false</c>.</value>
    Public ReadOnly Property Enabled() As Boolean
        Get
            Try
                Dim loReg As RegistryKey = Registry.ClassesRoot.OpenSubKey("callto", False)
                loReg.Close()
            Catch
                Return False
            End Try
            Return True
        End Get
    End Property
    ''' <summary>
    ''' Does the call.
    ''' </summary>
    ''' <param name="destination">The destination.</param>
    Public Sub DoCall(ByVal destination As String)

        If Not Enabled Then Throw New ApplicationException("Callto is not enabled")
        Process.Start("callto://" & destination)

    End Sub

End Class

 

Download Sample

Sketchflow – “Duplicate” Bug

Standard

 

image

 

The Problem

At the moment I’m trialling Sketchflow for Expression Blend.  There’s an annoying bug that happens when you use the “Duplicate” action on a node:

image

If you use this action, sooner or later you’ll end up with this error:

‘InitializeComponent’ is not a member of ‘xxxxxxxxxx.xxxxxxxxxxxxxx’

This can be very frustrating if you are trying to advocate Sketchflow as a prototyping tool for non wpf savvy analysts.

The Workaround

The simplest workaround is to delete the code-behind file.  To do this, go to the project pane and choose “Delete”.

image

 

At first I tried hard to ensure that the xaml filenames and classnames were correct.  This just causes a cascading comedy of errors.

Upgrading Sketchflow prototype projects to real code is a pipe-dream at the moment.

If you know of a better way of handling this situation (and fixing the errors) more quickly, feel free to comment.  I just want get on with the prototyping.