UWP calling Office Interop APIs

Following up on what we talked about at BUILD, here is another scenario that is common for LOB Enterprise desktop app developers: Using Microsoft.Office.Interop.* APIs to automate tasks in Office apps installed on the desktop. I have put together a small sample that shows how this can be done from a UWP app on Windows 10 Anniversary Update and above. Hope this will be useful for folks who have existing code and skills in this space and want to move on to UWP.

What does the sample do? The task is to automate Excel with the interop APIs in order to populate a spreadsheet with the content of a Telerik data grid control in my UWP. This is a fairly simple example, but you get the idea how you can now utilize those APIs for Office automation from your UWP app package.

How does it work? The UWP is using the FullTrustProcessLauncher API from the Desktop extension SDK to activate a .NET component from its package that is making the calls to the Microsoft.Office.Interop.* APIs. We are using an AppService to communicate between the two parts of the app package.

Even though we are using a desktop-only API here, the UWP app can still be universal and run on all Windows 10 devices like Windows Phone, Surface Hub, Xbox, etc. – and light up the Office automation functionality on PC only.

screenshot

TL;DR
See source code on GitHub and/or get the demo app from the Store:
Get it on Windows 10

Details
First thing we need to do is extend our UWP app package with two extensions: (a) ‘windows.fullTrustProcess’ implemented in my Excel.Interop.exe and (b) ‘windows.appService’, which I will be running in-proc with my UWP – so no need to define an entry point for this one.

<Extensions>
  <uap:Extension Category="windows.appService">
    <uap:AppService Name="ExcelInteropService" />
  </uap:Extension>
  <desktop:Extension Category="windows.fullTrustProcess"
                     Executable="Win32\Excel.Interop.exe" />
</Extensions>

 

The Excel.Interop.exe component now simply connects to our AppService and waits for requests. When the service gets closed, the component will exit.

static void Main(string[] args)
{
    // connect to app service and wait until the connection gets closed
    appServiceExit = new AutoResetEvent(false);
    InitializeAppServiceConnection();
    appServiceExit.WaitOne();
}

static async void InitializeAppServiceConnection()
{
    connection = new AppServiceConnection();
    connection.AppServiceName = "ExcelInteropService";
    connection.PackageFamilyName = Package.Current.Id.FamilyName;
    connection.RequestReceived += Connection_RequestReceived;
    connection.ServiceClosed += Connection_ServiceClosed;

    AppServiceConnectionStatus status = await connection.OpenAsync();
}

 

When a request comes in from the UWP app, we’ll handle it and do as we are told by calling the Microsoft.Office.Interop.* APIs.

private async static void Connection_RequestReceived(
   AppServiceConnection sender,
   AppServiceRequestReceivedEventArgs args)
{
    string value = args.Request.Message["REQUEST"] as string;
    string result = "";
    switch (value)
    {
        case "CreateSpreadsheet":
            try
            {
                // call Office Interop APIs to create the Excel spreadsheet
                Excel.Application excel = new Excel.Application();
                excel.Visible = true;
                Excel.Workbook wb = excel.Workbooks.Add();
                Excel.Worksheet sh = wb.Sheets.Add();
                sh.Name = "DataGrid";
                sh.Cells[1, "A"].Value2 = "Id";
                sh.Cells[1, "B"].Value2 = "Description";
                sh.Cells[1, "C"].Value2 = "Quantity";
                sh.Cells[1, "D"].Value2 = "UnitPrice";

                for (int i = 0; i < args.Request.Message.Values.Count / 4; i++)
                {
                    CreateLineItem(sh, i, args.Request.Message);
                }
                result = "SUCCESS";
            }
            catch (Exception exc)
            {
                result = exc.Message;
            }
            break;
        default:
            result = "unknown request";
            break;
    }

    ValueSet response = new ValueSet();
    response.Add("RESPONSE", result);
    await args.Request.SendResponseAsync(response);
}

 

How does the code look on the UWP client side? Very simple – once the connection is established, we can send down the content of our table (as a ValueSet) to the Excel.Interop component via the AppService connection.

private async void MainPage_AppServiceConnected(object sender, EventArgs e)
{
    // send the ValueSet to the fulltrust process
    AppServiceResponse response =
        await App.Connection.SendMessageAsync(table);

    // check the result
    object result;
    response.Message.TryGetValue("RESPONSE", out result);
    if (result.ToString() != "SUCCESS")
    {
        MessageDialog dialog = new MessageDialog(result.ToString());
        await dialog.ShowAsync();
    }
}

 

Thanks for reading this far. Hope this was helpful and you can use it to build great solutions with UWP. Questions, feedback, concerns or cheers? Please leave them in the comments or hit me up on twitter @StefanWickDev.

Advertisements

18 thoughts on “UWP calling Office Interop APIs

  1. Can apps with FullTrustProcessLauncher be uploaded to the Windows Store? Right now I’m using brokered compoent to be able to communicate with my .NET apps but unfortunately, that app won’t be valid in the Store.

    Like

  2. Using Visual Studio 2017, I successfully deployed your Grid2Excel sample app on my Windows 10 Pro. When I opened your DataGrid2Excel.sln file in VS2017, I noticed that the solution has two projects: “Grid2Excel” UWP app and “Excel.Interop” an interop app. I was wondering if we can achieve something similar for a Visual Studio Tools for Office (VSTO) project in VS2017. Any thoughts or suggestions? Or, you think we have not gotten that far in UWP world “yet”.

    Like

    1. Can you clarify the scenario you want to accomplish? Do you want to call into your own Office plugin from your UWP app? The short answer is: if you can do it from a regular Win32/.NET app then you can do it from a UWP as well using the same technique as demonstrated in this post.

      Like

      1. I have an MS WORD 2016 Add-in that I created using VSTO project template in “VS2017 – ver 15.9.5” on my “Windows 10 Pro – ver 1809” desktop. Now I want to publish that Add-in to Microsoft Store by somehow wrapping it into a UWP package. From what I’ve heard so far is that it’s still in a wish list of MS team. But after working on your Grid2Excel sample I started thinking may be there is a light at the end of tunnel. Publishing that VSTO add-in to Microsoft Store is my utmost dream-come-true desire. Add-in is only for MS Office 2016 desktop edition. The add-in does include a WinForm for user inputs etc. I can easily re-write the WinForm into a UWP app; and I don’t worry about that.

        Moreover, I cannot convert that Add-in to new Office web add-in because of some limitations on the new Office web add-in technology. Please let me know if you have any suggestions/thoughts/questions etc.

        Like

    1. The project type is .NET Framework Console application. Be sure to set the output type to “Windows Application” in the project properties to avoid showing the actual console.

      Like

  3. Thanks for the article. This is exactly what I need. However, when I download the sample and compile I get sever errors such as the following:

    The type forwarder for type ‘Windows.ApplicationModel.AppService.AppServiceConnection’ in assembly ‘Windows’ causes a cycle

    The type name ‘AppServiceConnection’ could not be found in the namespace ‘Windows.ApplicationModel.AppService’. This type has been forwarded to assembly ‘Windows, Version=255.255.255.255 …

    I’m sure there is something simple that I’m missing, but I can’t figure out what it might be.

    Thanks.

    Like

      1. Hmm, not sure what’s wrong with that project. I created it two years ago against older versions of VS and Windows SDK. Looks like something got stale here since then. However, if I create a new Console app, copy the code and add the references it compiles fine. I’d suggest you do the same to get unblocked while we fix the sample in GitHub. The references you need to add are:
        %ProgramFiles(x86)%\Microsoft Visual Studio\Shared\Visual Studio Tools for Office\PIA\Office15\Microsoft.Office.Interop.Excel.dll
        %ProgramFiles(x86)%\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll
        %ProgramFiles(x86)%\Windows Kits\10\UnionMetadata\10.0.17763.0\Windows.winmd

        Like

  4. This worked. I got the project to compile and run. However, when I click “Export to Excel,” I get the following error:

    “The Appx package’s manifest is invalid. (Exception from HRESULT: 0x80080204)”

    Could you please tell me what might cause this? I am investigating but have had no luck so far.

    Thanks!

    Like

      1. Actually, I literally just now got it to work! Thanks so much for this blog post and your additional help. Your sample will enable me to include a feature in my app that the users really want while sticking with UWP.

        Like

  5. I am getting the same problem as Matt. I made a new c# and c++ .net console app, and it does not recognize
    using Windows.ApplicationModel.AppService;

    It seems the Windows namespace does not exist.

    Maybe Matt can share his code.

    Like

  6. I no longer get the error message and have not gotten to the test the app but i wanted help anybody else having the same problem. It appears that VS19 needs to have the following reference:

    c:\Program Files (x86)\Windows Kits\10\UnionMetaData\Windows.winmd

    Right click on the project,
    Add Reference->Browse
    Add that file. (Note the file browser will have a filter that does not include .winmd — set to all)

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s