Silver Light and Blue Sky

C# and Infrastructure. Code is everything.

P/Invoke in .NET Core on Red Hat Enterprise Linux

This post was originally published on Red Hat Developers, the community to learn, code, and share faster. To read the original post, click here.

P/Invoke(Platform Invocation Service) is one of the features of CLI (Common Language Interface) on .NET Framework. P/Invoke enables managed code to call a native function in DLL (Dynamic Link Library). It’s a powerful tool for .NET Framework to execute existing C-style functions easily. .NET Core also has a P/Invoke feature and it means we can call a native function in .so file (Linux) and . file (Max OSX). I will show you the short example P/Invoke in .NET Core on Red Hat Enterprise Linux (RHEL).

Here is the simple P/Invoke sample using read function in libc. It is the same way as .NET Framework on Windows to import native function.

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace ConsoleApplication
{
    public class Program
    {
        [DllImport("libc")]
        static extern int read(int handle, byte[] buf, int n);

        public static void Main(string[] args)
        {
            Console.Write("Input value:");
            var buffer = new byte[100];
            read(0, buffer, 100);
            Console.WriteLine("Input value is:" + Encoding.UTF8.GetString(buffer));
        }
    }
}

[dllimport] is the attribute to import a native function. We can declare method name as a native function name, and declare method name as you like with specifying native function name in EntryPoint attribute value as below.

[DllImport("libc", EntryPoint="read")]
static extern int Read(int handle, byte[] buf, int n);

We can read text from console input with native libc method.

Next, I’d like to execute GUI sample written in .NET Core on RHEL. .NET Core doesn’t have GUI Framework at this point. However, we can call GUI library such as gtk+ from managed code in .NET Core. At first, install the package.

$ sudo yum install gtk3-devel

Now we can call functions in gtk+ from C# code. Here is the whole code to open dialog from C#.

using System;
using System.Runtime.InteropServices;

namespace ConsoleApplication
{
    public class Program
    {
        [DllImport("libgtk-x11-2.0.so.0")]
        private static extern void gtk_init (ref int argc, ref IntPtr argv);
        [DllImport("libgtk-x11-2.0.so.0")]
        static extern IntPtr gtk_message_dialog_new(IntPtr parent_window, DialogFlags flags, MessageType type, ButtonsType bt, string msg, IntPtr args);
        [DllImport("libgtk-x11-2.0.so.0")]
        static extern int gtk_dialog_run(IntPtr raw);
        [DllImport("libgtk-x11-2.0.so.0")]
        static extern void gtk_widget_destroy(IntPtr widget);
        [Flags]
        public enum DialogFlags 
        {
            Modal = 1 << 0,
            DestroyWithParent = 1 << 1,
        }

        public enum MessageType
        {
            Info,
            Warning,
            Question,
            Error,
            Other,
        }
        
        public enum ButtonsType
        {
            None,
            Ok,
            Close,
            Cancel,
            YesNo,
            OkCancel,
        }

        public static void Main(string[] args)
        {
            var argc = 0;
            var argv = IntPtr.Zero;
            gtk_init(ref argc, ref argv);
            var diag = gtk_message_dialog_new(IntPtr.Zero, DialogFlags.Modal, MessageType.Error, ButtonsType.Ok, "Hello from .NET Core on Red Hat!", IntPtr.Zero);
            var res = gtk_dialog_run(diag);
            gtk_widget_destroy(diag);
            Console.WriteLine(res);
        }
    }
}

Here is a result. The dialog is opened.

f:id:tanaka733:20160915095221p:plain

P/Invoke was a technology only for Windows platform, but now it enables many platforms to call native function easily from managed code. Of course, we shouldn’t forget Mono, which enabled P/Invoke on Linux.

How to queue and cancel build from C# code with VSTS Nuget library

Overview

Visual Studio Team Services has an API, so we can queue and cancel build via API.

Visual Studio Team Services and Team Foundation Server REST API Reference

Here is an API about the build.

Builds | REST API Reference for Visual Studio Team Services and Team Foundation Server

Microsoft provides four NuGet libraries for VSTS API.

.NET Client Libraries for Visual Studio Team Services (and TFS)

Microsoft.TeamFoundationServer.Client is the library to execute build operation. However, it's hard to use. I write sample codes for queuing and cancelling build.

Queue build

Here is a sample.

gist.github.com

QueueBuildAsync, which is a method to queue a build, has the Build object as a parameter. Build object has many properties. However, there is no document which property is required. I found Definition.Id (id of build definition) and Project property are necessary after several tries.

Cancel build

Next, I'd like to cancel the queued build from C# code. What do I do? There is no API in the list. "Delete" method is not the API for cancelling but for deleting the completed build itself.

The answer is executing "update" method. We should update the queued build status to "cancel".

gist.github.com

We should execute two or more API calls to queue or cancel build. That's the way to execute them from C# code.

Getting session source information at RDP session by C#

I'd like to get the information of remote session source at the destination server with this function*1.

WTSQuerySessionInformation function (Windows)

It can be written by C# with DllImport. The value of WTS_CURRENT_SESSION is uint.MaxValue.

gist.github.com

It takes some doing because the structure of ppBuffer is changed depending on the specified value in WTSInfoClass. Here is a struct when WTSInfoClassis WTSClientAddress.

WTS_CLIENT_ADDRESS structure (Windows)

If you get all the sessions except itself, you can use this function.

WTSEnumerateSessions function (Windows)

*1:It seems OK for launching app with UAC elevation

3 issues for using PSCmdlet binary module

I use PSCmdlet binary module code with C# in order to automate operation on Windows Server. Development with C# and execution speed are the pros for me. However there are issues I can't ignore. I will describe these issue and I wish PSCmdlet binary module solve these issues in the near future.

f:id:tanaka733:20150407010038p:plain

Poor compatibility with async/await and Rx (Reactive Extensions)

If I call async method or Rx Observable method in Cmdlet and call Write-Object after await, errors like below sometime occur.

The WriteObject and WriteError methods cannot be called from outside the overrides of the BeginProcessing, ProcessRecord, and EndProcessing methods, and only from that same thread. Validate that the cmdlet makes these calls correctly, or please contact Microsoft Support Services.

This is due to SynchronizationContext.Current is null in Cmdlet class.

To solve this, one idea is providing custom SynchronizationContext. AwaitablePSCmdlet is a good solution by sunnyone.

A base class that enables to use async/await (cf http://sunnyone41.blogspot.jp/2014/06/pscmdletasyncawait.html)

Another idea for using Rx is implementing producer-consumer pattern with BlockingCollection.

gist.github.com

Difficult to configure Assembly Binding

The assembly binding is sometime required when I use 3rd-party library in Cmdlet class

Configuring Assembly Binding Redirection

In my case, Google APIs Client library is the case. I must configure in app.config as below.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.2.22.0" newVersion="4.2.22.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

However, it is difficult to configure assembly binding in PSCmdlet binary module. Here is a stackoverflow thread about this.

stackoverflow.com

To solve this issue, we should configure GAC and powershell.exe.config. But it is hard to accept because it influences the entire operating system. I'd like to configure separately for each module or process, but I can't find any solution so far.

Difficult to load configuration file

This is the same issue of previous one as in terms of app.config. If I want to provide configuration to Cmdlet from app.config as well as Console Application, it is difficult to configure. Only global powershell.exe.config is effective for configuration.

stackoverflow.com

To configure appdomain's configuration is one solution. But I worry about by-effect in appdomain. So, in my case Cmdlet receives app.config path and parse xml and pass configurations to logic class as below.

gist.github.com

I understand this solution is only valuable if logic class can receive configuration directly (without ConfigurationManager).

Summary

These 3 issues are critical for me to use PSCmdlet binary module. However PSCmdlet is necessity for automating in Windows Server. I will approach better solution for these.