WPF Application Incorporating WinAPI (Win8) components - c#

I have a WPF application which utilizes a handwriting control.
By using an
<InkCanvas></InkCanvas>
In my XAML, I was able to get the user's strokes, and turn them into text using the InkAnalysis class. However, this is strictly 32bit, and my requirements dictate a 64bit build.
Unable to find a 64bit compatible library, I looked into upgrading to .NET 4.5 and utilizing the Windows8 classes which are available to desktop apps (by also adding
<TargetPlatformVersion>8.1</TargetPlatformVersion> to the csproj file so that I could add the 'Windows' namespace references). Luckily, Windows.UI.Input.Inking is.
However, when I add the reference to Windows.UI.Input.Inking, I get a build error which states:
Unknown build error, 'Cannot resolve dependency to Windows Runtime type 'Windows.Foundation.Metadata.PlatformAttribute'. When using the ReflectionOnly APIs, dependent Windows Runtime assemblies must be resolved on demand through the ReflectionOnlyNamespaceResolve event.'
I have looked into the:
Windows.Foundation.Metadata.PlatformAttribute
And it seems to want an enum member, either:
Windows.Foundation.Metadata.Platform.Windows
or
Windows.Foundation.Metadata.Platform.WindowsPhone
This is a desktop application, so I would obviously choose to target Platform.Windows, but cannot figure out how to tell the compiler this.
How can I incorporate this Windows.UI.Input.Inking class into my WPF application? My end goal is simply to convert strokes from the inkcanvas into text, in a 64 bit environment.

I discovered that I was receiving this error due to the reference added to the:
Windows.UI.Input.Inking
library. It seems that the correct way to add reference to Windows 8/8.1 WinAPI components (from a non WinAPI application) is the following:
Add <TargetPlatformVersion>8.1</TargetPlatformVersion> to the csproj file
Add reference to the Windows library (this is the key - adding the specific lib, in this case, Windows.UI.Input.Inking, causes the build error)
Add the more specific (ex: Windows.UI.Input.Inking) reference in the actual file where the API is required
I am working on creating a NuGet package which will edit the csproj file, and add the Windows reference. I'll update this if/when it is completed.

Related

Xamarin.Forms App crashes on iOS when installed via Testlfight

Hello fellow developers!
I am developing a Xamarin.Forms App for android and iOS.
It works fine in Debug and Release mode on Android Emulators, Android Devices, iOS Emulators.
But there is a problem with iOS Devices. Directly deploying the Debug/Release Builds to a device works. But when I upload the app to the AppStore and install it via Testflight on my device, it crashes on startup.
From the console I can see following errors:
"System.MissingMethodException: Default constructor not found for type App.Views.Login"
"Default constructor not found for type ColorPicker.iOS.Effects.ColorPickerTouchEffectiOS"
The first one is related to my Login View, which has a default constructor and works fine in debug and release builds.
The second one is related to a nugget package.
My question is:
Why are the default constructors available in Debug and Release but not when i download the app via Testflight? And how can I fix this?
Linking behaviour is set to "Link all".
That's because when you use the Link all assemblies option you need to manually preserve the classes in your project and potentially mark out library code that isn't linker safe.
There is a Microsoft document specifically catering to this question : https://learn.microsoft.com/en-us/xamarin/ios/deploy-test/linker?tabs=macos
You could set your linker behaviour to Link SDK assemblies only temporarily while you manually get ready for a full link.
Preservin code:
When you use the linker it can sometimes remove code that you might have called dynamically either using System.Reflection.MemberInfo.Invoke, or by exporting your methods to Objective-C using the [Export] attribute and then invoking the selector manually.
In those cases, you can instruct the linker to consider either entire classes to be used or individual members to be preserved by applying the [Xamarin.iOS.Foundation.Preserve] attribute either at the class-level or the member-level. Every member that is not statically linked by the application is subject to be removed. This attribute is hence used to mark members that are not statically referenced, but that are still needed by your application.
Skipping Assemblies
It is possible to specify assemblies that should be excluded from the linker process, while allowing other assemblies to be linked normally. This is helpful if using [Preserve] on some assemblies is impossible (e.g. 3rd party code) or as a temporary workaround for a bug.
--linkskip=NameOfAssemblyToSkipWithoutFileExtension // Single assembly
--linkskip=NameOfFirstAssembly --linkskip=NameOfSecondAssembly // Multiple Assemblies
Hope this helps. Make sure you go through the MS doc for more details

Does ApiInformation not respect the app target version

Imagine the following setup:
UWP Library:
MinVersion: 10240
TargetVersion: 16299
This library checks at runtime if the UniversalApiContract Version 5 is present.
If yes, it will use the new NavigationView control that.
UWP App:
MinVersion: 10240
TargetVersion: 10240
This app references the UWP Library project.
When I run this app on my Computer, which has Windows 10 Version 16299 installed, the following happens:
The UWP Library checks at runtime for the api contract. As I have the newest version of Windows 10, yes it is present.
Then it tries to create the NavigationView control, and I get a TypeLoadException with the message Could not find Windows Runtime type 'Windows.UI.Xaml.Controls.NavigationView'.
What? Why? Does the ApiInformation class not respect the target version of the running app?
What can I do to work around this issue?
I thought ApiInformation was the way to avoid this, but apparently not?!
Here is a Github repository showcasing the error:
https://github.com/haefele/ApiInformationTargetVersionFail
If you set the target-version of the MyApp project to 16299, everything works fine.
[Edit May 29 2018]
The methods of the ApiInformation type are based on a trivial lookup of the WinRT metadata on disk -- if the metadata is there, the call succeeds. This enables "light-up" of new features on new platforms without increasing your minimum version. What's important though is that ApiInformation knows nothing about the implementation of the API: sometimes it might be missing (eg on early "Insider" builds of the OS) and sometimes it might not work due to "quirks" (see example below). .NET also had a different view of the world due to the way the JIT and .NET Native toolchains work.
This can cause problems...
.NET apps use a concept of a "Union WinMD" which is the union of all known types (including Extension SDKs) that exist in the Windows SDK that corresponds to the MaxVersionTested setting of the app. If you're running the app on a down-level platform, ApiInformation will tell you the API doesn't exist, but .NET can still JIT methods based on the Union WinMD and perform some reflection tasks. If you actually try and call the API (because you forgot the ApiInformation check) you will get a MissingMethodException at runtime because the API doesn't really exist.
A different problem can occur if you include a higher-versioned .NET library inside a lower-versioned app and then try to run it on the higher-versioned build of the OS. In this case, ApiInformation will succeed because the type exists in the system metadata, but .NET will throw a MissingMethodException at runtime because the type didn't exist in the Union WinMD used to build the app.
Important: This is based on the Target Version (aka MaxVersionTested) of the app, not the library!
If you build a release version of the app, you will even see the .NET Native toolchain display a warning such as this in the Output window:
warning : ILTransform : warning ILT0003: Method 'Foo.Bar()' will always throw an exception due to the missing method 'SomeNewType.NewMethod()'. There may have been a missing assembly.
There is no good way around this, other than to build your application with the same target version as the library (so that it can resolve all the references).
Another problem you can encounter is when your app (or a library it consumes) use APIs "from the future" that didn't exist in the OS listed as the MaxVersionTested of the app. Many of the APIs will work, but some don't due to incompatibilities with the simulated legacy mode the app is running in.
Hypothetical example of the library problem
Imagine that version X of the OS only supported black-and-white apps, where the background is always white and text, graphics, etc. are always black. Apps are built using this underlying assumption - including having graphics buffers that allocate only 1-bit-per-pixel, or never worrying about text being invisible because the background and foreground colours are the same. Everything is fine.
Now version Y of the OS comes out, and it supports colour graphics (say, 8-bits-per-pixel). Along with this new feature comes a pair of new APIs, SetForegroundColor() and SetBackgroundColor() that let you choose whatever colour you want. Any app (or library) that asks ApiInformation whether these two new APIs exists will succeed on version Y of the OS, and any app with a MaxVersionTested of at least Y can use them successfully. But for compatibility reasons they cannot work in an app that only targeted version X because it has no idea colours exist. Their graphics buffers are the wrong size, their text might become invisible, and so on. So the APIs will fail at runtime when used in an X-targeted app, even though the OS has the metadata (and the implementation) to support them.
Unfortunately there is no good way of handling this situation today, but it is a relatively rare occurrence. It is equivalent to a legacy Win32 library using LoadLibrary / GetProcAddress (or a legacy .NET library using reflection) to discover APIs that are "from the future."

How to handle new releases of third-party .Net assemblies without recompiling?

I have some projects that rely on external .Net assemblies to operate. These are installed externally from my program so I do not have direct control over what version is being used. Furthermore, updates are expected to be installed as a matter of course.
For example, in one case I am accessing a hardware device that provides a .Net interface to control it. When the user initially installs the device, they install the driver that is included. This driver when I wrote the program may have been 3.0.4.0. The latest version might be 3.1.8.0.
My program fails to load the assembly when this happens complaining that the manifest definition is incorrect. A specific exception message is show below.
Another example is a labeling program. They provide a .Net interface to allow my program to print labels through their system. Installing an updated version of the program is fatal.
Here is the specific exception message:
Could not load file or assembly 'SDK.NET.Interface, Version=17.1.0.0,
Culture=neutral, PublicKeyToken=865eaf3445b2ea56' or one of its
dependencies. The located assembly's manifest definition does not match
the assembly reference.
If I install this version of the application on my computer, then reference the updated version of the assembly and compile, I’m good to go . . . for now.
But, it’s only a matter of time before I will have the issue again.
I’ve tried setting the Specific Version property of the referenced assemblies to False but that didn’t affect the problem.
What is the proper way to address the issue?
You are able to "Plug and Play" as long as method signatures don't change.
If those change, then you'll need to fix your base code.
Look at Microsoft's documentation on Redirecting Assembly Versions:
http://msdn.microsoft.com/en-us/library/7wd6ex19%28VS.71%29.aspx
Another option is If these libraries are somehow controlled by you or your company, you might have some wiggle room with reflection by loading them up by their base type/interface and using common methods... but you'll need to have access to the base types.
This is also a duplicate question:
Upgrade a reference dll in a C# project without recompiling the project
Upgrading dependent DLL without recompiling the whole application

Using ApplicationData in Windows WPF vs UWP

Semi-important Background
I am attempting to change a UWP project to a Windows desktop application so that I can make use of the full .NET Framework 4.5.2. My solution also contains a second project--a Windows Runtime Component--which operates the background tasks. These background tasks write to the ApplicationData so that the primary project with the GUI can use the information. I've made the primary project a Windows application rather than a UWP, but one issue remains:
The Issue
Any reference to ApplicationData.Current.LocalSettings.Values such as
ApplicationData.Current.LocalSettings.Values.Keys.Contains(myDataIndex)
results in the following error:
Error CS0012 The type 'IPropertySet' is defined in an assembly that is not referenced. You must add a reference to assembly
'Windows.Foundation.FoundationContract, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime'. ProjectName C:\Users\MyUserName\Documents\Visual Studio 2015\Projects\ProjectName\ProjectName\MainWindow.xaml.cs
So, for some reason, VS is confused on what IPropertySet is.
I've Tried...
Unfortunately, there's nothing starting with Windows.Foundation in the list of namespaces under Assemblies->Framework in the Reference Manager.
Ok, so it's probably already in there somewhere, right...? I'll just try using the required namespace. However, my project cannot find this Windows.Foundation.FoundationContract because my project does not allow
using Windows.Foundation.FoundationContract
though it does find Windows.Foundation.Diagnostics and Windows.Foundation.Metadata.
When I tried this in the original UWP version of the project, it was able to find Metadata, Diagnostics, and Windows.Foundation.Collections. (Curiously enough, the IPropertySet interface my Windows app can't find is actually located in Windows.Foundation.Collections).
This leads me to think that Windows.Foundation.Collections is not available in the .NET Framework used by the Windows app, and only in the UWP .NET Core...? But if that's the case, why does VS still know about ApplicationData.Current.LocalSettings.Values if it couldn't be used? It seems as if I'm missing something else here.
Update
It looks like I just needed to import
C:\Program Files (x86)\Windows Kits\10\UnionMetadata\Windows.winmd
per this answer to fix the reference issues.
(Strangely, I also had to remove a reference to another Windows.winmd file that was at another path. I think that was somehow a result of my attempts to import other things.)
Real Question
Ok, I made it work, but it seems like I'm cheating by importing UWP library stuff. But surely there's a better way?
TL;DR
How am I supposed to use ApplicationData for cross-thread data-sharing in a WPF desktop application without other imports? (And how is it different than a UWP application?

How to create a generic use library

I have an image editor user control(c# .net v2.0). Its used in thousands of computers as an activex component. I want the component also be available for windows forms and possible other uses.
For activex usage i add <object> tag in html code and call the component with clsid(a static guid). So if i build and distribute a newer version it works without changing any client code.
I want windows forms to be able use the same distributed libraries. And they should not reference a specific version so i can update the component without changing the programs that use it.
I use regasm to register for com. But i dont know how to reference it from visual studio(like referencing with clsid?)
May be in visual stuido when i choose add reference and select COM tab i shuld see my component in the list.
note: i tried to add the assemly to the global cache using these lines but it did not work out-or i coulnt understand if anything has changed :)
"C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\tlbexp" ImageEditorComp.dll /out:ImageEditorComp.tlb
regasm /tlb:ImageEditorComp.tlb ImageEditorComp.dll
"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\gacutil" /I ImageEditorComp.dll
Any suggestions appreciated,
Regards
This is not possible, you'll invoke the infamous and dreaded DLL Hell problem. A stone cold hard rule in COM is that you have to change the [Guid] attribute values on public interfaces when you make a breaking change in either the publicly visible interfaces or the implementation of them. Changing the guids ensures that you don't overwrite the registry keys of an old version of your component when you use Regasm.exe. Existing programs that use your component and were not recompiled to use the latest version will continue running without problems. The typical outcome of DLL Hell is a nasty hardware exception like AccessViolation, very difficult to troubleshoot.
None of which applies in your specific case here. There is no point in trying to use the component through COM. It is a .NET assembly, just add the reference to it directly. The IDE will in fact stop you from adding a reference to the interop library. But not the .tlb. The GAC keeps you out of DLL Hell, assuming you properly increment [AssemblyVersion].
I figured out a solution.
To explain step by step:
1- Create the component with all needed properties for com.(Sign the assembly, use interfaces for com, make assembly com visible)
On the client machine
2- Register the assembly with regasm(i recommend adding safety flags too).
3- Add the assembly to the global cache using gacutil(or msi installer)
I figured out when you call a specific version of an assembly gac is searched in the first place so if its installed in GAC, referenced codebase path is never used.
When using as activeX you address the component with GUID. Since regasm adds the assembly name and version the GUID is representing, web browser directly uses component from GAC.
When using from a desktop application, reference the assebmly directly and set copylocal property to false. Similarly, in the client machine windows will find the assembly located at GAC itself.
Here is a useful link about the subject.
http://www.simple-talk.com/dotnet/visual-studio/build-and-deploy-a-.net-com-assembly/
Hope it saves other peoples time :)

Categories