Category Archives: Solution

The New JumpList API for Windows 10 Universal App

Recently, the JumpList API for UWP app has been released:

UWP-JumplistSee Jump list customization sample: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/JumpList

The sample shows the following techniques:

  • Disable the jump list.
  • Create a jump list based on Recent or Frequent items.
  • Adding tasks to the jump list.
  • Creating groups of items in a jump list.
  • Perform an action when a jump list item is activated by the user.

Notice that not all platforms support this API. We can check if we can skip saving your custom jump list content. On unsupported platforms, save does not do anything and the API will always load a default empty jump list.

Use this method to check if the platform is supported

Two Things You Need to Know About Microsoft Advertising SDK in WinRT

The Microsoft Advertising SDKs allow developers to show ads in their apps (Windows Phone/Windows Store apps). With these SDKs developers can create apps that present a rich and engaging advertising experience for their users.
Microsoft has pointed out some known issues in MSDN document:
Known Issues – Microsoft Advertising SDK for Windows Phone: https://msdn.microsoft.com/en-us/library/advertising-mobile-windows-phone-known-issues(v=msads.20).aspx
Known Issues – AdControl for Windows 8.1: https://msdn.microsoft.com/en-us/library/advertising-windows-known-issues%28v=msads.10%29.aspx

Recently, we have got some feedbacks from our customers, this article will describe two things which not be clearly mentioned in the above two documents.

1. The page navigating will stop working in C++ Hub App after adding the Microsoft Advertising AdControl

A customer created a C++ HUB demo using VS template and added ADControl, he encountered a weird issue when navigating to other page with this exception:

Microsoft C++ exception: Platform::FailureException ^ at memory location 0x0140E560. HRESULT:0×80004005 Unspecified error

It will cause app crashing. This issue does not exist in C#/Vb.net Hub app

The most likely explanation is mentioned in the “Known Issues – AdControl for Windows 8.1” document:

C++
No Native Support: The current Ad SDK does support .NET C++ (managed C++ using the CLR). The AdControl loads the CLR and uses managed C++. Fully native support is planned for a future release — there is no release ETA.

The workaround is just setting Window::Current::Content directly instead of using Frame->Navigate method

2. “OcrEngine is not registered” exception when creating a new OcrEngine instance

(1) Download the official Microsoft OCR Library Sample(C# version): https://code.msdn.microsoft.com/Uses-the-OCR-Library-to-2a9f5bf4

(2) In Visual Studio, select PROJECT | Manage NuGet Packages. In the Online section, select nuget.org. Search for Microsoft.Windows.Ocr. Click Install.

(3) Add reference to “Microsoft Advertising SDK for Windows Phone 8.1 (XAML)” and set Windows Phone as the Start project

(4) Add Try Catch structure outside of this line: ocrEngine = new OcrEngine(OcrLanguage.English); in the Scenario1_ExtractTest.xaml.cs file
Like this:

try
{
       ocrEngine = new OcrEngine(OcrLanguage.English);
}catch(Exception ex)
{
       Debug.WriteLine(ex.Message); //Add break point at here
}

(5) Start debugging on the emulator, everything will be fine

(6) Now debug on the real device, click on scenario select button, you will see the error message:
exception1

This issue is not caused by the Advertising SDK, an expert from Microsoft OCR Team has pointed out that it seems like classes are not being pulled out of the winmd file for insertion into the final .appxmanifest file. It looks like a known issue with VS 2013 Update 4 that should be fixed with Update 5.

The workaround is to add extension entry for OcrEngine class manually to the .appxmanifest file:

<Package>
    ...
    <Extensions>
        <Extension Category="windows.activatableClass.inProcessServer">
            <InProcessServer>
                <Path>WindowsPreview.Media.Ocr.dll</Path>
                <ActivatableClass ActivatableClassId="WindowsPreview.Media.Ocr.OcrEngine" ThreadingModel="both" />
            </InProcessServer>
        </Extension>
     </Extensions>
</Package>

Be Careful With Backslash in WMI Query String

Background & Issue:

Recently, a customer encountered a issue:

He removed a volume’s drive letter which label was “AAA” in the Disk Management(Win+R -> diskmgmt.msc)

Now, getting the free space of this volume is what he wanted, as we know, each volume has GUID to identify itself, so this customer create a method to obtain volume GUID by label, it used WMI query:

internal string GetDriveGuidByLabel(string driveLabel)
{
            using (ManagementObjectSearcher ms = new ManagementObjectSearcher(String.Format("Select * From Win32_Volume Where Label = '{0}'", driveLabel)))
            {
                foreach (var mo in ms.Get().Cast<ManagementObject>())
                {
                    return mo["DeviceID"].ToString();
                }
            }
            return null;
}

The result like this: \\?\Volume{2c6c2c33-987b-11e3-8257-806e6f6e6963}\

Next, after getting the volume GUID, to retrieve the information of this volume, WMI query could accomplish this:

SELECT * FROM Win32_Volume WHERE DeviceID = '\\\\?\\Volume{2c6c2c37-987b-11e3-8257-806e6f6e6963}\\'

He created a method:

internal Int64 GetDriveAvailableSpaceByDriveGuid(string driveGuid)
{
            // The commented line below does not work - returns InvalidQuery System.Management.Exception no matter what I tried.
            using (ManagementObjectSearcher ms = new ManagementObjectSearcher(String.Format("Select * from Win32_Volume Where DeviceID = '{0}'", driveGuid)))
            {
                ManagementObject mo = ms.Get().Cast<ManagementObject>().First();
                return Int64.Parse(mo["FreeSpace"].ToString());
            }
            return 0;
}

But it didn’t work with exception as below:

An unhandled exception of type ‘System.Management.ManagementException’ occurred in System.Management.dll
Additional information: Invalid query

Troubleshoot & Solution:

At first, I used WMI Code Creator to verify WMI query string: Utility Spotlight: WMI Code Creator

The WMI query string was correct. I noticed that there were some backslashes inside the volume GUID, generally, we need to use a verbatim string literal @”…” to prevent the backslash being treated as an escape sequence in C#, like this:

ManagementObjectSearcher searcher = new ManagementObjectSearcher(@"SELECT * FROM Win32_Volume WHERE DeviceID = '\\\\?\\Volume{2c6c2c37-987b-11e3-8257-806e6f6e6963}\\'");

For this customer’s method, we need to use String.Replace() method for avoiding exception:

internal Int64 GetDriveAvailableSpaceByDriveGuid(string driveGuid)
{
            using (ManagementObjectSearcher ms = new ManagementObjectSearcher(String.Format("Select * from Win32_Volume Where DeviceID = '{0}'", driveGuid.Replace("\\", @"\\"))))
            {
                ManagementObject mo = ms.Get().Cast<ManagementObject>().First();
                return Int64.Parse(mo["FreeSpace"].ToString());
            }

            
            return 0;
}

Screenshot:
GetDriveAvailableSpaceByDriveGuid

Using the Bing Maps REST Services To Obtain the Route in the .NET Application

The Bing Maps platform provides multiple API options for your application including an AJAX control, a Windows Store apps control, a WPF control, REST Services, and Spatial Data Services. See more information: http://www.microsoft.com/maps/choose-your-bing-maps-API.aspx

To obtain the route data, Bing Maps REST Services is our choice: http://msdn.microsoft.com/en-us/library/ff701713.aspx

The Bing™ Maps REST Services Application Programming Interface (API) provides a Representational State Transfer (REST) interface to perform tasks such as creating a static map with pushpins, geocoding an address, retrieving imagery metadata, or creating a route.

About using the REST Services with .NET, this article is helpful: http://msdn.microsoft.com/en-us/library/jj819168.aspx

Here is my WPF sample:

XAML:

<Grid>
        <m:Map Name="myMap" 
               Center="-1.968404, 30.036240" 
               ZoomLevel="10"
               CredentialsProvider="Fill Your Key"
               Mode="AerialWithLabels" ></m:Map>

        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Bottom">
            <Label Content="From: " FontWeight="Bold" />
            <TextBox Width="80" Height="20" Name="fromTxb" Text="New York" />
            <Label Content="To: " FontWeight="Bold" />
            <TextBox Width="80" Height="20" Name="toTxb" Text="Seattle" />
            <Button Content="Route" Width="80" Click="RouteButton_Click" />
        </StackPanel>
    </Grid>

Using the following method to request route data from REST Services:

private void Route(string start, string end, string key, Action<Response> callback)
{
            //Culture c = CultureDD.SelectedItem as Culture;
            Uri requestURI = new Uri(string.Format("http://dev.virtualearth.net/REST/V1/Routes/Driving?wp.0={0}&wp.1={1}&rpo=Points&key={2}", Uri.EscapeDataString(start), Uri.EscapeDataString(end), key));
            //QueryURLTbx.Text = requestURI.AbsoluteUri;
            GetResponse(requestURI, callback);
}

private void GetResponse(Uri uri, Action<Response> callback)
{
            try
            {
                HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                    using (Stream stream = response.GetResponseStream())
                    {
                        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Response));

                        if (callback != null)
                        {
                            callback(ser.ReadObject(stream) as Response);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
}

Getting the credential:

private void GetRoute(string fromloc, string toloc)
{
            string to = toloc;//"Seattle";
            string from = fromloc;//"New York";

            if (!string.IsNullOrWhiteSpace(from))
            {
                if (!string.IsNullOrWhiteSpace(to))
                {
                    GetKey((c) =>
                    {
                        Route(from, to, c, (r) =>
                        {
                            if (r != null &&
                                r.ResourceSets != null &&
                                r.ResourceSets.Length > 0 &&
                                r.ResourceSets[0].Resources != null &&
                                r.ResourceSets[0].Resources.Length > 0)
                            {
                                Route route = r.ResourceSets[0].Resources[0] as Route;

                                double[][] routePath = route.RoutePath.Line.Coordinates;
                                LocationCollection locs = new LocationCollection();

                                for (int i = 0; i < routePath.Length; i++)
                                {
                                    if (routePath[i].Length >= 2)
                                    {
                                        locs.Add(new Microsoft.Maps.MapControl.WPF.Location(routePath[i][0], routePath[i][1]));
                                    }
                                }

                                MapPolyline routeLine = new MapPolyline()
                                {
                                    Locations = locs,
                                    Stroke = new SolidColorBrush(Colors.Red),
                                    StrokeThickness = 5
                                };

                                myMap.Children.Add(routeLine);

                                myMap.SetView(locs, new Thickness(30), 0);
                            }
                            else
                            {
                                MessageBox.Show("No Results found.");
                            }
                        });
                    });
                }
                else
                {
                    MessageBox.Show("Invalid End location.");
                }
            }
            else
            {
                MessageBox.Show("Invalid Start location.");
            }
}

Screenshot(gif):
WpfBingMapsRoute

Download Sample: WpfBingMapsRoute

To get the Bing Maps Trial Key, please go to here: http://www.microsoft.com/maps/

Here are some Bing Maps resources, please refer to: Bing Maps Resources

Always Use Plain Type(e.g. char*) As Parameter For P/Invoke

Background:

Recently, a customer encountered a strange issue. He created a C++ class library with I/O operation:

Source File:

#include "stdafx.h"
#include
#include

#include "DynamicDLLToCall.h"
using namespace std;

void zlog(string fstr)
{
	FILE * debug;
	debug = fopen("zlog.txt", "a");
	ifstream iFile(fstr);
	fprintf(debug, "fsadfsdfsdfsdfdsfsdf");
	fclose(debug);
}

Header File:

using namespace System;
using namespace std;

extern "C" __declspec(dllexport) void zlog(string fstr);

Now, he want to call zlog() method in a .NET project:

[DllImport("D:/ClassLibrary1.dll")]
public static extern void zlog(string fstr);//imported func

private void Button_Click(object sender, RoutedEventArgs e)
{
            zlog("asdas");
}

Issue:
This app crashed when the zlog() function is called and the zlog.txt file was successfully created.

Troubleshoot:

At first, I tried to comment some code snippets in the zlog(string fstr) function, but this issue still existed, so I think it should be more related to the declaration of this function.

With the help from C++ expert, it may be caused by this reason: C++ doesn’t support(or fully support) ABI(Application Binary Interface) which is required to help clean the stack of the object.

What is ABI? Please refer to these references:

ABIs cover details such as:

–the sizes, layout, and alignment of data types

–the calling convention, which controls how functions’ arguments are passed and return values retrieved; for example, whether all parameters are passed on the stack or some are passed in registers, which registers are used for which function parameters, and whether the first function parameter passed on the stack is pushed first or last onto the stack

–how an application should make system calls to the operating system and, if the ABI specifies direct system calls rather than procedure calls to system call stubs, the system call numbers

–and in the case of a complete operating system ABI, the binary format of object files, program libraries and so on.

A complete ABI, such as the Intel Binary Compatibility Standard (iBCS),[1] allows a program from one operating system supporting that ABI to run without modifications on any other such system, provided that necessary shared libraries are present, and similar prerequisites are fulfilled.

——–

So always use plain type(e.g. char*) as parameter for P/invoke instead of using type within the std namespace as parameter.

The following code worked well now:

C++ declaration:

extern "C" __declspec(dllexport) void zlog(char* fstr);
1

C++ function:
1
void zlog(char* fstr)
{
 //...your code
}

In .NET application code behind:

[DllImport("DynamicDLLToCall", CallingConvention = CallingConvention.Cdecl)]
public static extern void zlog(string fstr);