UWP C# app calling Windows Runtime Component written in C++ - c++

I am trying to create a Windows Runtime(WinRT) Component written in C++(c++-cx) which can be called from my UWP C# app. I followed this MSDN Tutorial
It all went fine. I am able to build & run the code/sample specified in the above link on both Windows-10 Desktop & Mobile
I then tried to create a even simpler WinRT Component. I followed the same steps as above tutorial. Created a Windows Runtime Component project (File->New->Project->Visual C++ ->Windows->Universal->Windows Runtime Component(Universal Windows))
Now my class has only one function, getNum which basically returns a uint16
This is my Class header file
#pragma once
#include <collection.h>
namespace WRT_sample
{
public ref class Class1 sealed
{
public:
Class1();
uint16 getNum();
};
}
This is the corresponding cpp file:
#include "Class1.h"
using namespace WRT_sample;
using namespace Platform;
Class1::Class1()
{
}
uint16 Class1::getNum()
{
return 100;
}
I am using the same class names(Class1.h & Class1.cpp) which VS-2015 provides when I create a new WinRT project.
This is how I make a call to WinRT class from my C# code:
namespace CS_WRT_sample
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
initWRT();
}
void initWRT()
{
try
{
var nativeObj = new Class1();
var num = nativeObj.getNum();
this.Result2.Text = "Num from Cpp: " + num.ToString();
Debug.WriteLine("Num from Cpp: " + num);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
this.Result3.Text = ex.Message;
}
}
}
}
I am able to build & run my code on Desktop(x86/x64 Local Machine), but when I try to run on Mobile(x86 Emulator or ARM device), it fails with the following error:
Exception thrown: 'System.IO.FileNotFoundException' in CS_WRT_sample.exe
The specified module could not be found. (Exception from HRESULT: 0x8007007E)**
This is the stack trace which I see:
System.StubHelpers.StubHelpers.GetWinRTFactoryObject(IntPtr pCPCMD)
at WRT_sample.Class1..ctor()
at CS_WRT_sample.MainPage.initWRT()
My VS-2015 details:
MS Visual Studio Professional 2015
Version 14.0.25123.00 Update 2
MS .NET Framework
Version 4.6.01038
I am not sure, why I am hitting the issue, as I followed the same steps mentioned in the MSDN tutorial.
Any help will be highly appreciated.

You will run into this if you use a direct reference to a C++ winmd, instead of a P2P reference. This is easy to check in your .csproj:
For example, your .csproj should not have this line:
..\Debug\Abc_def\Abc_Def.winmd
Instead, consider using something like:
{1ee77824-eaa8-40f1-9b56-6f8ffa44e727}
Abc_Def

Related

c++/cli dll wrapper for native c++ to be used in LabView

I'm trying to write a c++/cli wrapper for IO Industries Core2 DVR, which will then be used by LabView. The company provided a SDK with with all the headers (written in c++) and boost library. I've managed to build a wrapper that builds and LabView is able to see the function through the .net pallet.
// ManagedProject.h
#pragma once
#include "core_api_helper.h"
#include "core_api.h"
using namespace System;
using namespace CoreApi;
namespace ManagedProject {
//Setup class
public ref class Setup
{
private:
public:
unsigned int initializeTest();
};
}
// This is the DLL Wrapper.
#include "stdafx.h"
#include "ManagedProject.h"
#include "core_api_helper.h"
#include "core_api.h"
#include "resource.h"
using namespace CoreApi;
using namespace Common;
using namespace ManagedProject;
//Global handles
//A handle to the Core Api
InstanceHandle g_hApi;
//A handle to the Core Api Device Collection
DeviceCollectionHandle g_hCoreDeviceCollection;
unsigned int Setup::initializeTest()
{
try
{
//Initialize the Core API (must be called before any other Core API functions)
//Returns a handle to the Core Api
g_hApi = Instance::initialize();
// get a collection of Core devices
g_hCoreDeviceCollection = g_hApi->deviceCollection();
unsigned int deviceCount = g_hCoreDeviceCollection->deviceCount();
return deviceCount;
}
catch (GeneralException& e)
{
e.what();
return 3;
}
}
However when I run LabView through Visual studio 2015 in debug mode I run into the problem below, and what is returned to LabView is the 3 from the catch block.
First break in debug mode (NULL ptr)
NOTE: InstanceHandle is a shared_ptr
As can be seen the variable is a NULL pointer, the same thing happens for the g_hCoreDeviceCollectoin as well. I think I need to Instantiate it with the new command but am a little unsure as InstanceHandle is a shared_ptr.
Any help would be much appreciated
The C++/CLI has great feature called mixed mode. You can uses both managed and native data types in the same code (in the same C++/CLI class). Try to use object from that SDK written in C++ directly in your wrapper.

C++ and VBA: Building a registration-free COM DLL?

in short:
Is it possible to create a C++-based COM component that I can reference and use from VBA, without needing to register the DLL (in windows registry)?
In long:
I'm a COM novice, so maybe what I'm tryong to do here structurally doesn't work or doesn't make sense, but:
I want to create a C++ COM library that is usable from VBA registration-free.
So I've created an C++ ATL project in VS, added a custom COM type (MyClass) and added a test method to it ("AddNumbers", taking 2 long parameters and returning 1).
When building this project, I'm getting an error "Failed to register output. Please try anebling Per-User Redirection or register the component from a comment prompt with elevated permissions", likely because I'm running Visual Studio without admin permissions. However, the DLL builds fine, I assume it's just not registered after building it.
Right, so when I reference this DLL in my VBA project (Tools -> Referewnces -> Browse... and add), intellisesne works, i.e. VBA knows the type "MyClass", knows it has a method "AddNumbers" and so on.
But, it can't instantiate it:
Sub test()
Dim q As MyClass
Set q = New MyClass ' This will fail: "Run-time error '429': ActiveX component can't create object"
End Sub
Why is that? Am I right in assuming it likely fails because this COM component isn't properly registered on the machine?
If so, can I somehow circumvent this? I've read some infos about registration-free .NET based COM components, but I have no idea if this also works - or is even needed?! - for C++ based components.
MyClass.h
// MyClass.h : Declaration of the CMyClass
#pragma once
#include "resource.h" // main symbols
#include "ATLProject4_i.h"
#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
#endif
using namespace ATL;
// CMyClass
class ATL_NO_VTABLE CMyClass :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMyClass, &CLSID_MyClass>,
public IDispatchImpl<IMyClass, &IID_IMyClass, &LIBID_ATLProject4Lib, /*wMajor =*/ 0xFFFF, /*wMinor =*/ 0xFFFF>
{
public:
CMyClass()
{
}
DECLARE_REGISTRY_RESOURCEID(106)
BEGIN_COM_MAP(CMyClass)
COM_INTERFACE_ENTRY(IMyClass)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
public:
STDMETHOD(AddNumbers)(LONG Num1, LONG Num2, LONG* ReturnVal);
};
OBJECT_ENTRY_AUTO(__uuidof(MyClass), CMyClass)
MyClass.cpp
// MyClass.cpp : Implementation of CMyClass
#include "stdafx.h"
#include "MyClass.h"
// CMyClass
STDMETHODIMP CMyClass::AddNumbers(LONG Num1, LONG Num2, LONG* ReturnVal)
{
// TODO: Add your implementation code here
*ReturnVal = Num1 + Num2;
return S_OK;
}

C++ dll in hololens

I am working creating a hololens application using a native code dll based on c ++. The problem comes when I add it in the unity project (plugins / WSA / x86).
When generating the UWP solution in Visual Studio I get a failure of DllNotFound.
From what I have been able to read, it is necessary to create a UWP library to use it in my application. That library must contain my native code. The truth is that I'm not sure how to do that. Is there any way to stop my dll based on c ++ on a UWP dll ??
error: System.DllNotFoundException: Unable to load DLL 'nativoHololensPrueba.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E).
C++
SOURCE:
#include <iostream>
#include <stdio.h>
#include <memory>
#include "Header.h"
__declspec(dllexport)
int testo() {
return 10;
}
HEADER:
extern "C" {
__declspec(dllexport)
int testo();
}
c#
[DllImport("nativoHololensPrueba")]
public static extern int testo();
// Use this for initialization
public GameObject texto;
void Start () {
texto.GetComponent<TextMesh>().text = "Cambiando el nombre " + testo();
}
I also had this and I solved it by compiling the dll on ARM64 (or ARM) with /MT flag.

CreatePushNotificationChannelForApplicationAsync in native C++

I'm trying to use windows push notifications in native C++ code. But I struggle with implementation. I'm calling CreatePushNotificationChannelForApplicationAsync but it returns
HRESULT_FROM_WIN32(ERROR_NOT_FOUND) : Element not found.
My OS is Win10 and I use Visual Studio 2015.
Here is my code:
#include <wrl.h>
#include <windows.networking.pushnotifications.h>
#include <ppltasks.h>
#pragma comment(lib, "runtimeobject.lib")
using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Networking::PushNotifications;
using namespace concurrency;
int main(char* argv[], int argc)
{
RoInitializeWrapper init(RO_INIT_MULTITHREADED);
if ( FAILED(init) )
return 0;
ComPtr<IPushNotificationChannelManagerStatics> channelManager;
HRESULT hr = GetActivationFactory(HStringReference(L"Windows.Networking.PushNotifications.PushNotificationChannelManager").Get(), &channelManager);
if ( FAILED(hr) )
return 0;
IAsyncOperation<PushNotificationChannel*>* asyncOp;
hr = channelManager->CreatePushNotificationChannelForApplicationAsync(&asyncOp); // return HRESULT_FROM_WIN32(ERROR_NOT_FOUND)
if ( FAILED(hr) )
return 0;
// create task to obtain uri from asyncOp
return 0;
}
On the other hand it is pretty straightforward in WinRT.
namespace WnsPushAPI
{
public ref class WnsWrapper sealed
{
public:
void ObtainUri()
{
IAsyncOperation<PushNotificationChannel^>^ channelOperation = PushNotificationChannelManager::CreatePushNotificationChannelForApplicationAsync();
auto channelTask = create_task(channelOperation);
channelTask.then([this](PushNotificationChannel^ channel) {
// ... Save URI for latter use. channel->Uri->Data()
channel->PushNotificationReceived += ref new TypedEventHandler<PushNotificationChannel^, PushNotificationReceivedEventArgs^>(this, &WnsWrapper::OnNotify);
}, task_continuation_context::use_current());
}
void OnNotify(PushNotificationChannel^ sender, PushNotificationReceivedEventArgs^ e)
{
// do something
};
};
}
I also checked generated code with /d1ZWtokens compiler switch but I didn't find anything useful.
Documentation for push notification for native C++ is really poorly written and I couldn't find and example in native C++.
Your code is okay. The problem lies in the fact that you can only register for push notifications from Windows Store applications. You cannot do that from desktop applications. The error comes from the fact that the system cannot find your AppX package identity.
I also faced same HRESULT_FROM_WIN32(ERROR_NOT_FOUND) error while trying to use WNS from my desktop app. Just in case anyone also faces this issue I'd like to mention CreatePushNotificationChannelForApplicationAsync works fine from Desktop Bridge. Here is the code that I used. Note it is winrt based, and I think WRL based code also would work without any problem, just need to wrap desktop app with Desktop Bridge.
winrt::init_apartment();
PushNotificationChannelManagerForUser manager = PushNotificationChannelManager::GetDefault();
IAsyncOperation<PushNotificationChannel> async = manager.CreatePushNotificationChannelForApplicationAsync();
async.Completed([](auto && result, auto && status) {
auto channel = result.GetResults();
});

Use C++/CLI Library in C++ native code and how to link

I want to use some code that executes a http-post, and because I'm not too familiar with c++ and what libraries you can use, and I am probably too dumb to get libcurl and curlpp to work, I found a link explaining how to use the .net version.
Alright so I created a class. Header File:
public ref class Element
{
public:
Element();
virtual ~Element();
void ExecuteCommand();
};
Class file:
#include "Element.h"
Element::Element()
{
}
Element::~Element()
{
Console::WriteLine("deletion");
}
void Element::ExecuteCommand(){
HttpWebRequest^ request = dynamic_cast<HttpWebRequest^>(WebRequest::Create("http://www.google.com"));
request->MaximumAutomaticRedirections = 4;
request->MaximumResponseHeadersLength = 4;
request->Credentials = gcnew NetworkCredential("username", "password", "domain");
HttpWebResponse^ response = dynamic_cast<HttpWebResponse^>(request->GetResponse());
Console::WriteLine("Content length is {0}", response->ContentLength);
Console::WriteLine("Content type is {0}", response->ContentType);
// Get the stream associated with the response.
Stream^ receiveStream = response->GetResponseStream();
// Pipes the stream to a higher level stream reader with the required encoding format.
StreamReader^ readStream = gcnew StreamReader(receiveStream, Encoding::UTF8);
Console::WriteLine("Response stream received.");
Console::WriteLine(readStream->ReadToEnd());
response->Close();
readStream->Close();
}
If I set the configuration type of this project to Application (exe), and create a new .cpp file where I create an Instance of this Element it works fine.
But my question is: Is it possible to create a .dll/.lib Library from this project and use it in a C++ project without CLI? (I don't want to use ^ for pointers :( )
Even if it's not possible, I have another problem.
When I link the library in a C++/CLI project. I get
unresolved token (06000001) Element::.ctor
unresolved token (06000002) Element::~Element
unresolved token (06000003) Element::ExecuteCommand
3 unresolved externals
the code for main.cpp in the second project is just the following:
#include <Element.h>
int main(){
return 0;
}
Thank you
As Hans Passant already stated: you must compile your C++/CLI code as Dynamic Library in order to be able to consume it from an unmanaged application. CLI/Managed code cannot run from/cannot reside in static libraries.
If you change the C++/CLI library target from Static library to Dynamic library you'll be able to compile successfully your unmanaged C++ application.
One thought from my side:
I think you'll be better if you use mixed mode C++/CLI DLLs to consume the managed functionality - you'll be able to free your consumer application completely from referencing the CLR.
The Header of such mixed mode Wrapper for your Element class would look like this:
#pragma once
#pragma unmanaged
#if defined(LIB_EXPORT)
#define DECLSPEC_CLASS __declspec(dllexport)
#else
#define DECLSPEC_CLASS __declspec(dllimport)
#endif
class ElementWrapperPrivate;
class __declspec(dllexport) ElementWrapper
{
private:
ElementWrapperPrivate* helper;
public:
ElementWrapper();
~ElementWrapper();
public:
void ExecuteCommand();
};
And the implementation would look like this:
#include "ElementWrapper.h"
#pragma managed
#include "Element.h"
#include <msclr\auto_gcroot.h>
using namespace System::Runtime::InteropServices;
class ElementWrapperPrivate
{
public:
msclr::auto_gcroot<Element^> elementInst; // For Managed-to-Unmanaged marshalling
};
ElementWrapper::ElementWrapper()
{
helper = new ElementWrapperPrivate();
helper->elementInst = gcnew Element();
}
ElementWrapper::~ElementWrapper()
{
delete helper;
}
void ElementWrapper::ExecuteCommand()
{
helper->elementInst->ExecuteCommand();
}
Then just compile your Element.cpp + ElementWrapper.cpp to a DLL and use the ElementWrapper.h in your unmanaged applications.