Click here to Skip to main content
15,885,278 members
Articles / Programming Languages / C#

Implementing Windows Runtime interfaces in C#, C++/CX and C++/WRL

Rate me:
Please Sign up or sign in to vote.
4.88/5 (7 votes)
21 Apr 2013CPOL2 min read 31.3K   239   19   1
Creating interfaces with identical functionality (method and properties) in various languages

Introduction

In the recent releases of Microsoft* Visual Studio 2012 and Windows 8* with Windows Runtime as a common foundation, there are many new things to investigate. This article demonstrates how to implement interfaces with equal set of methods and properties in various languages. This can be valuable in iterative development or just helpful in better understanding interfaces in Windows Runtime.

Background

In order to estimate syntax complexity and details of interfaces implementations with further comparison of results, a small task, solving a small problem, was taken since small things with equal functionality are easy to compare. Moreover, the results of compilation into MSIL are also included.

Using the code

A given sample idea stems from a Hybrid JavaScript and C++ online Visual Studio sample. It contains a UI JavaScript project and 3 worker projects. The worker projects are respectively implemented in C#, C++/CX and C++/WRL and the UI project is in JavaScript. Each worker project interlaces the picture with its own method and returns the calculation time through its elapsedTime property.

From JavaScript code the functionality looks as follows:

JavaScript
// JavaScript consumer
var myObject = new ImagingNamespace.ImageFilter();
myObject.interlaceImage(srcFile.path, dstImgPath); // a method
var calcTime = myObject.elapsedTime;               // a property

Interfaces

First, this is an IDL interface for C++/WRL. It looks almost as a regular COM interface with a few new details:

MIDL
[uuid(c350a862-0132-4da5-86b2-db0b47bc6913),
version(COMPONENT_VERSION)]
interface IImageCustomProcessing : IInspectable
{
    HRESULT InterlaceImage([in] HSTRING inFile, [in] HSTRING outFile);
    [propget] HRESULT ElapsedTime([out, retval] DOUBLE* pVal);
}

This is the result of compilation of the interface into IL:

MSIL
.class interface public auto ansi abstract flag(4000) ImagingCppNative.IImageCustomProcessing
{
    .custom instance void [Windows.Foundation]Windows.Foundation.Metadata.VersionAttribute::.ctor(uint32) = (
        01 00 00 00 00 01 00 00
    )
    .custom instance void [Windows.Foundation]Windows.Foundation.Metadata.GuidAttribute::.ctor(
            uint32,  uint16,  uint16,  uint8,  uint8,  uint8,  uint8,  uint8,  uint8,  uint8,  uint8) = (
        01 00 62 a8 50 c3 32 01 a5 4d 86 b2 db 0b 47 bc
        69 13 00 00
    )
    .property instance float64 ElapsedTime()
    {
        .get instance float64 ImagingCppNative.IImageCustomProcessing::get_ElapsedTime()
        {
        }
    }

    .method public hidebysig newslot abstract virtual 
        instance void InterlaceImage (
            [in] string inFile,
            [in] string outFile
        ) cil managed 
    {
    }
}

C++/CX interface is implemented in the following way:

MC++
public interface class IImageCustomProcessing
{
    void InterlaceImage(String^ inFile, String^ outFile);
    property double ElapsedTime { double get(); }
};

The corresponding IL is below:

MSIL
.class interface public auto ansi abstract flag(4200) ImagingCppCX.IImageCustomProcessing
{
    .custom instance void [Windows]Windows.Foundation.Metadata.VersionAttribute::.ctor(uint32) = (
        01 00 01 00 00 00 00 00
    )
    .custom instance void [Windows]Windows.Foundation.Metadata.GuidAttribute::.ctor(uint32, 
            uint16,  uint16,  uint8,  uint8,  uint8,  uint8,  uint8,  uint8,  uint8,  uint8) = (
        01 00 d4 3e d0 d8 70 23 11 3b be 25 82 40 3e 81
        01 52 00 00
    )
    .property instance float64 ElapsedTime()
    {
        .get instance float64 ImagingCppCX.IImageCustomProcessing::get_ElapsedTime()
        {
        }
    }

    .method public hidebysig newslot abstract virtual 
        instance void InterlaceImage (
            string inFile,
            string outFile
        ) cil managed 
    {
    }
}

The C# interface looks as usual:

C#
public interface IImageCustomProcessing
{
    void InterlaceImage(String inFile, String outFile);
    double ElapsedTime { get; }
}

IL for this interface:

MSIL
.class interface public auto ansi abstract flag(4000) ImagingCS.IImageCustomProcessing
{
    .custom instance void [Windows]Windows.Foundation.Metadata.VersionAttribute::.ctor(uint32) = (
        01 00 00 00 00 01 00 00
    )
    .custom instance void [Windows]Windows.Foundation.Metadata.GuidAttribute::.ctor(uint32,  
             uint16,  uint16,  uint8,  uint8,  uint8,  uint8,  uint8,  uint8,  uint8,  uint8) = (
        01 00 72 2c c0 d1 59 00 d9 50 63 5f 66 f4 3e 7f
        60 91 00 00
    )
    .property instance float64 ElapsedTime()
    {
        .get instance float64 ImagingCS.IImageCustomProcessing::get_ElapsedTime()
        {
        }
    }

    .method public hidebysig newslot abstract virtual 
        instance void InterlaceImage (
            [in] string inFile,
            [in] string outFile
        ) cil managed 
    {
    }
}

It's not hard to notice that the resulting MSIL for all languages is almost completely equal, no matter which language has been used.

Classes

This section describes how to bring these interfaces to life and to make them actually work.

The IDL interface in C++/WRL is implemented in the following manner:

C++
class ImageFilter : public RuntimeClass<::ABI::ImagingCppNative::IImageCustomProcessing>
{
    InspectableClass(RuntimeClass_ImagingCppNative_WinRTImageProcComponent, TrustLevel::BaseTrust);

    ...
    // Declaration
public:
    IFACEMETHOD(InterlaceImage)(_In_  HSTRING inFile, _In_  HSTRING outFile);
    IFACEMETHOD(get_ElapsedTime)(DOUBLE *time);
    
    ...
}
ActivatableClass(ImageFilter);

C++/CX implementation looks like this:

MC++
public ref class ImageFilter sealed : IImageCustomProcessing
{
    ...
public:
    // Declaration
    virtual void InterlaceImage(String^ inFile, String^ outFile);
    virtual property double ElapsedTime
    {
        double get() { return elapsedTime; } // and even implementation
    }
    ...
}

The C# code is the simplest:

C#
public sealed class ImageFilter : IImageCustomProcessing
{
    ...
    public void InterlaceImage(String inFile, String outFile)
    { ... }

    public double ElapsedTime
    {
        get { return elapsedTime; }
    }
    ...
}

C# implementation remark

C# in .NET 4.5 targeting Metro UI (or Microsoft design language, or with WinMD output) is made in such a way that all IO operations are asynchronous. Therefore, the special trick has been done to make loading and unloading synchronous and align the code idea with C++ pieces.

The following code snippet runs an asynchronous piece of code in a synchronous method.

C#
int SyncMethod()
{
    var asyncTask = new TaskFactory().StartNew(async () =>
        {
            // some async code
            return 0;
        });
    var syncTask =     asyncTask.ContinueWith(/* no async here */tt =>
        {
            /// This small catch makes this task really synchronous
            return tt.Result.Result;
        });

    syncTask.Wait();
    
    int taskResult = syncTask.Result

    return taskResult;
}

Please notice that the lambda function in StartNew constructor is asynchronous and on the contrary the lambda function in ContinueWith is regularly synchronous. In this case, taskResult will be assigned only after asyncTask and syncTask both finish.

Conclusion

As a result, interfaces with completely equal functionality may be created in different languages and notably resulting MSIL code for different interfaces looks equal, no matter which tool--IDL, CL or CSC--has been used.

History

December 15, 2012 - Initial publishing.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
Anton possess a great hands-on 10+ year development experience in a number of areas from assembler to web development.

Recently he relocated to Bay Area as a consultant to help companies bring their ideas to life.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Nish Nishant21-Dec-12 6:13
sitebuilderNish Nishant21-Dec-12 6:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.