TypeLoadException using WinRT Brokered Component - c#

I am building a Windows Store App using a brokered component. The brokered component is meant to enable interaction with an RFID reader on the device. When I try to initialize an instance of the class exposed by the brokered component, I received a System.TypeLoadException with the message Could not find or load a type. (Exception from HRESULT: 0x80131522).
I'm working against a clean installation of Windows 8.1 Professional on two different tablet devices. Both are currently experiencing this issue. The solution has worked in the past; something I've done recently must be causing this. I've also verified that the RFID reader can be accessed using a sample application provided by the hardware vendor.
My Package.appxmanifest file looks similar to this:
<Package ...>
...
<Extensions>
<Extension Category="windows.activatableClass.inProcessServer">
<InProcessServer>
<Path>clrhost.dll</Path>
<ActivatableClass ActivatableClassId="MyApp.RFID.Component.RfidDevice" ThreadingModel="STA">
<ActivatableClassAttribute Name="DesktopApplicationPath" Type="string" Value="C:\Program Files (x86)\MyApp\RFID" />
</ActivatableClass>
</InProcessServer>
</Extension>
</Extensions>
</Package>
The solution is being built to target an x86 platform. I've registered my components on the target device under C:\Program Files (x86)\MyApp\RFID using the following commands (per this whitepaper):
icacls . /T /grant "ALL APPLICATION PACKAGES":RX
regsvr32 MyApp.RFID.Proxy.dll
I've installed the Visual Studio 2013 x86 Redistributable Package on the target device. I've also placed an additional dependency .dll in the same directory, just as I have been doing during all of my development.
Some other things I've tried:
Using %PROGRAMFILES% instead of C:\Program Files (x86) as the value for the ActivatableClassAttribute in the manifest.
Using 'STA', 'MTA', and 'Both' as the threading models.
Added a trailing slash to the ActivatableClassAttribute value path.
Completely uninstalled everything and tried again from scratch.
Explicitly add an empty default constructor to the RfidDevice class.

Related

UWP LaunchFullTrustProcessForCurrentAppAsync - EXE file not found

We are creating a UWP application which is intended for Side loading only.
At various times this application needs to reboot the PC (it's desktop only), to do this we intend to use LaunchFullTrustProcessForCurrentAppAsync() to call a simple external EXE which uses Process.Start("shutdown") to reboot the PC.
We have created the EXE called RebootPC.exe and on it's own it works fine.
We now include it in our UWP project:
First we add the desktop and rescap namespaces to our project and we also add rescap to our IgnorableNamspaces
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap mp uap5 rescap">
Then, we then modify the Extension section to include our EXE, we know we cannot put the EXE in our project root as C# compiler removes it so we have put it in a sub folder (in this case \Assets). We also set the EXE's type to 'Content' and 'Copy always' in the Solution explorer
<desktop:Extension Category="windows.fullTrustProcess" Executable="Assets\RebootPC.exe">
<desktop:FullTrustProcess>
<desktop:ParameterGroup GroupId="rebooter" Parameters=""/>
</desktop:FullTrustProcess>
</desktop:Extension>
finally in the manifest we add rescap to the Capabilities section - we know it has to be first in the list otherwise you get a manifest error when packaging
<Capabilities>
<rescap:Capability Name="runFullTrust"/>
<Capability Name="internetClient" />
<DeviceCapability Name="bluetooth" />
<DeviceCapability Name="radios" />
OK, so the manifest is changed. We now go to our C# code:
In that we perform the following:
if (ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0))
{
try
{
await Windows.ApplicationModel.FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
When we build and run the project in Visual Studio it seems to work fine, under the intended circumstances the PC will reboot as intended.
The problem comes when we try to package it for installation on other PCs. We use Store->Create App Packages (remember this application is for side loading only).
The creation of the package works fine and we can install it on other PCs with no problem. The problem is that when we run the Application and it comes time to run the external EXE to reboot the PC a command window opens but we get an exception saying "System can't find c:\users.......\Assets\RebootPC.exe"
So, even though the packaging is done without error and even though we have set the properties of RebootPC.exe to 'Content' and 'Copy always' it is either not being included in the package or not being installed along with the App?
So, does anyone know how we can check if it is being included in the package? and if so how we can check if and where it is being installed on the target machine? or has anyone else had this issue and found the solution?
This has had us baffled for days and is driving us crazy!!!
UPDATE: I think the issue may not be that RebootPC.exe can't be found but rather shutdown.exe - If this is the case then it's a bit of a school boy error!!!
Anyway, I will sort this and see if that fixes the issue
I will leave the rest of the question up as it might provide useful information for others
As Mentioned in the official sample the exe file has to in the Appx folder of your project
Make sure the RebootPC.exe was copied to the Appx folder -
UWP\bin\x64\Release\AppX if not rebuild the solution or copy it
manually.
https://github.com/Microsoft/DesktopBridgeToUWP-Samples/tree/master/Samples/AppServiceBridgeSample#builddeploy-and-run-the-sample
try
{
await Windows.ApplicationModel.FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync("rebooter");
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}

C# - Cortana voice commands to launch external application

I am trying to integrate different files and links to the Cortana voice commands using C#. Most of the applications are working fine when i copy those particular files in the Cortana voice command application folder but i am unable to launch an *.exe file (copied in the same folder). The usual error i am getting is access denied even after launching VS as admin. I am attaching the code line along with the error screenshot.
{"Abrir NAV", (Action)(async () => {
StorageFile file = await Package.Current.InstalledLocation.GetFileAsync(#"Microsoft.Dynamics.Nav.Client.exe");
await Launcher.LaunchFileAsync(file);
})
},
Cortana Error
You could not launch executable file from your UWP app directly.
MSDN document has mentioned this point:
This API also imposes several restrictions on what types of files it can launch. Many file types that contain executable code, for example .exe, .msi, and .js files, are blocked from launching. This restriction protects users from potentially malicious files that could modify the system. From launcher documentation.
According to your description, your ".exe" file was contained in your UWP project. So, you could use the FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync() method to activate the full-trust Win32 component of an application from a Universal Windows app component in the same application package.
Please note the "full-trust" concept. You would need to declare "full-trust" for your ".exe" file in "Package.appxmanifest". For example:
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap= "http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
IgnorableNamespaces="uap mp rescap desktop">
<Applications>
<Application>
...
<Extensions>
<desktop:Extension Category="windows.fullTrustProcess" Executable="MyFiles\ConsoleApp1.exe"/>
</Extensions>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust"/>
</Capabilities>
</Package>
Then, in code, you could call this method to launch that ".exe" file.
await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();

64 bit side-loaded app to use Brokered Windows Runtime Components

I have a 32-bit (x86) side-loaded Windows Store app that works with a brokered Windows Runtime Component, it works smoothly and can launch desktop exe, load desktop dll using Reflection, etc.
I want to make this side-loaded app 64-bit. And after rebuilding the app as x64, it can never use the brokered Windows Runtime Component again. The error is
Additional information:
Unable to cast COM object of type 'StoreAppBrokeredWindowsRuntimeComponent.DirectInvoker' to interface type 'StoreAppBrokeredWindowsRuntimeComponent.IDirectInvokerClass'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{50EA3FD3-2383-5445-4002-8CBCBED5DB0F}' failed due to the following error: Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).
From the doc Brokered Windows Runtime Components for a side-loaded Windows Store app,
Side-loaded applications can be 64-bit (provided there is both a 64-bit and 32-bit proxies registered), but this will be atypical.
Question:
How to build a 64-bit proxy?
The VS template can only build 32 bit (Win32) proxy. If change the WindowsRuntimeProxyStub to x64, it cannot even be compiled - there are a bunch of LINK errors.
So 32-bit side-loaded app, 32-bit brokered Windows runtime component, and 32-bit proxy is the only working approach so far.
With the help of Microsoft Support, I have successfully built a 64 bit brokered runtime component and used it from a 64-bit side-loaded app.
To make it easier to follow, just use the following MS sample projects. You don't need to modify any code file at all. However, there are two errors in the template you need to fix first, see Important Notes at the end of this answer.
Brokered Windows Runtime Components for side-loaded Windows Store apps - Server
Brokered Windows Runtime Components for side-loaded Windows Store apps - Client
Steps to build 64-bit brokered component and proxy
Unzip the code package(Brokered Windows Runtime Components for side-loaded Windows Store apps - Server.zip) and open the solution with Visual studio 2013 (Run as Administrator);
Change the platform of SampleProxy project from Win32 to x64;
Open SampleProxy Property->Configuration Properties->Preprocessor->Preprocessor Definitions, and change two of definitions
WIN32->X64; REGISTER_PROXY_DLLWIN32->REGISTER_PROXY_DLL
Change the platform of EnterpriseIPCServer project to x64.
Edit Post-build event command line of EnterpriseIPCServer, replace each occurrence of x86 or Win32 with x64, the command should be like this:
call "$(DevEnvDir)..\..\vc\vcvarsall.bat" x64
md "$(TargetDir)"\impl
md "$(TargetDir)"\reference
erase "$(TargetDir)\impl\*.winmd"
erase "$(TargetDir)\impl\*.pdb"
rem erase "$(TargetDir)\reference\*.winmd"
xcopy /y "$(TargetPath)" "$(TargetDir)impl"
xcopy /y "$(TargetDir)*.pdb" "$(TargetDir)impl"
winmdidl /nosystemdeclares /metadata_dir:C:\Windows\System32\Winmetadata "$(TargetPath)"
midl /metadata_dir "%WindowsSdkDir%References\CommonConfiguration\Neutral" /iid "$(SolutionDir)SampleProxy\$(TargetName)_i.c" /env x64 /x64 /h "$(SolutionDir)SampleProxy\$(TargetName).h" /winmd "$(TargetName).winmd" /W1 /char signed /nologo /winrt /dlldata "$(SolutionDir)SampleProxy\dlldata.c" /proxy "$(SolutionDir)SampleProxy\$(TargetName)_p.c" "$(TargetName).idl"
mdmerge -n 1 -i "$(ProjectDir)bin\$(PlatformName)\$(ConfigurationName)" -o "$(TargetDir)reference" -metadata_dir "%WindowsSdkDir%References\CommonConfiguration\Neutral" -partial
rem erase "$(TargetPath)"
First build the EnterpriseIPCServer project.
Then build the SampleProxy project.
Check the output files (Fabrikam.winmd & SampleProxy.dll).
Steps to use the 64-bit brokered component and proxy
Tricky enough, the 64-bit brokered runtime component is never used at all. All we need is the 32-bit brokered runtime component, but we need to register both 32-bit and 64-bit proxy.
Put the 3 files (32-bit brokered runtime component + 2 proxies) under the same folder, for example, C:\test. Then execute the following commands.
regsvr32.exe C:\test\SampleProxy_64.dll (I have renamed the 64-bit proxy)
regsvr32.exe C:\test\SampleProxy.dll (this is the 32 bit proxy)
icacls C:\test /T /grant "ALL APPLICATION PACKAGES":RX
Then in the 64-bit side-load app, reference the 32-bit brokered runtime component. But be careful to pick the one in the "reference" folder, don't reference the one in the "impl" folder.
For your reference, I have uploaded the code to this GitHub repository.
Important Notes
There are some errors in this sample project, which make it a nightmare to build it for the x86/win32 configuration.
In the x86 configuration of EnterpriseIPCServer, the following command in the post build event contains an unrecognizable switch /x86, it should be /win32.
midl /metadata_dir "%25WindowsSdkDir%25References\CommonConfiguration\Neutral" /iid "$(SolutionDir)SampleProxy\$(TargetName)_i.c" /env win32 /x86 /h "$(SolutionDir)SampleProxy\$(TargetName).h" /winmd "$(TargetName).winmd" /W1 /char signed /nologo /winrt /dlldata "$(SolutionDir)SampleProxy\dlldata.c" /proxy "$(SolutionDir)SampleProxy\$(TargetName)_p.c" "$(TargetName).idl"
In the Win32 configuration of the SampleProxy project, one of the preprocessor definitions REGISTER_PROXY_DLLWIN32 should be REGISTER_PROXY_DLL.

Brokered components when using TFS Build

When using TFS to build my application, it fails when I have an application with Brokered components.
Here is what I am using in my Package.appxmanifest, and it works when I build/run locally. How can I still build/deploy using TFS and keep my brokered components? Is this possible?
<Extensions>
<Extension Category="windows.activatableClass.inProcessServer">
<InProcessServer>
<Path>clrhost.dll</Path>
<ActivatableClass ActivatableClassId="BrokeredRuntimeComponent.{ClassName}" ThreadingModel="MTA">
<ActivatableClassAttribute Name="DesktopApplicationPath"
Type="string"
Value="C:\Source\{AppName}\Debug\BrokeredRuntimeComponentProxy" />
</ActivatableClass>
</InProcessServer>
</Extension>
</Extensions>
When I run the build, I get the following error. I do not have access to run the regsvr32 /s on our TFS. Is this something that needs to be done on every client or can it be done on the build server and run on every device? I think it might work if it's possible to get the build service to run as administrator. Is this even possible?
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.CppCommon.targets (1620): Failed to register output. Please try enabling Per-user Redirection or register the component from a command prompt with elevated permissions.
Please let me know if anything I've put here is unclear so I can hopefully clarify.
You need to have everything installed on your build server that your need to run a build locally. If you need certain registered components then that needs done in advance or at build time.
If at build time then the account that TF build runs under needs permission to perform that action.

How to implement a Brokered Component: Windows Store App

Using the instructions from here: http://visualstudiogallery.msdn.microsoft.com/527286e4-b06a-4234-adde-d313c9c3c23e
Running Visual Studio 2013 as Admin with Update 2.
I create a C# BWRC project, TestBwrc. In Class.cs I add an int property that returns 1.
I add a new project to the solution, a C++ Brokered Windows ProxyStub called TestBwrc.Ps.
I add a reference to the TestBwrc project, and set project Linker properties to Register Output.
I then build the solution.
I add a new project to the solution, a C# blank windows store app, called TestBwrc.Client. I add a reference to the TestBwrc.Ps project.
Solution builds with no errors or warnings.
In the App.xaml.cs OnLaunched method I add TestBwrc.Class c = new TestBwrc.Class();
Visual Studio complains "Cannot resolve symbol 'Class'"
Solution builds with no errors or warnings.
Running the app throws an exception, TestBwrc.Class is not registered.
What am I missing?
Edit:
Also on TestBwrc.Client I added the Extensions tag to the app manifest with the ClassId of TestBwrc.Class and path Value of "..\Debug\TestBwrc.Ps"
The problem is the path Value of "..\Debug\TestBwrc.Ps" in the ActivateableClassAttribute as mentioned in my edit. Though %ProgramFiles% will be expanded, .. is not, nor is $(SolutionDir). So the for dev the only value that works is C:\dev\TestBwrc\Debug\TestBwrc.Ps
<Extensions>
<Extension Category="windows.activatableClass.inProcessServer">
<InProcessServer>
<Path>clrhost.dll</Path>
<ActivatableClass ActivatableClassId="TestBwrc.Class" ThreadingModel="MTA">
<ActivatableClassAttribute Name="DesktopApplicationPath" Type="string" Value="C:\dev\TestBwrc\Debug\TestBwrc.Ps" />
</ActivatableClass>
</InProcessServer>
</Extension>
</Extensions>

Categories