how to call uwp class library in win32 C++ console application - c++

I wanna call a uwp app with Uri in a win32 C++ console application.The first thing I thought is using LaunchUriAsync, but I couldn't find Windows.System.Launcher.LaunchUriAsync in win32 C++. So I wanna create a uwp class library to call LaunchUriAsync and win32 call this library. I find an example and now I can load the library sucessfully, but GetProcAddress always returns null. Not sure whether it is feasible calling uwp class library in win32 console. Pls help me out. The project is at https://github.com/vincent1000/win32CallUwpLibrary
The code is very simple:
UWP Classy Library:
namespace ExportedCodeSolution
{
public class Class1
{
[DllExport(ExportName = "callUri", CallingConvention = CallingConvention.StdCall)]
static public async void callUri()
{
Console.WriteLine("call URI start");
await Launcher.LaunchUriAsync(new Uri("www.bing.com"));
}
}
}
And Win32 Console:
using CallUriFn = void(__stdcall*) ();
int main()
{
HMODULE mod = LoadLibraryA("ExportedCodeSolution.dll");
CallUriFn fn = reinterpret_cast<CallUriFn>(GetProcAddress(mod, "callUri"));
fn();
}
Also, is any other method to call LaunchUriAsync in win32? I have searched some methods but none works for me.

The solution is trivial: Simply call Launcher.LaunchUriAsync from your console application. The easiest route is to use C++/WinRT. Assuming that you are using Visual Studio with the C++/WinRT extension installed, create a "Windows Console Application (C++/WinRT)", and replace the wizard generated code with this:
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.System.h>
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::System;
int main()
{
init_apartment();
Uri uri(L"www.bing.com");
Launcher::LaunchUriAsync(uri).get();
}
This will compile, but fail at runtime due to "www.bing.com" not being a valid URI. This needs to be replaced with a valid URI (e.g. "https://www.bing.com").

Related

Calling C# code from Windows Flutter desktop app

I am trying to call a function from a c# dll in a flutter desktop app,
In the C# dll I have,
using System;
using System.Runtime.InteropServices;
namespace MathLibrary
{
// NOTE: I have set set [assembly: ComVisible(true)] in AssemblyInfo.cs
[ComVisible(true)]
[Guid("66DE2FB9-7A3B-4C33-AF26-9AD5EDD4C71F")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IMathLibrary
{
[DispId(1)]
string multiply(int a, int b);
};
[ComVisible(true)]
[Guid("021E950E-3612-4FAD-9F15-F61632A95BD8")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("MathLibrary.MathCalc")]
public class MathCalc : IMathLibrary
{
public string multiply(int a, int b)
{
return "Product is " + (a * b).ToString();
}
}
}
I used this repo as the base flutter app.
In the app I have used platform channel to communicate between dart and c++ code. In c++ code I am trying to call the c# function (in file windows/runner/custom_channel.cpp).
After some googling, I came up with the following
First I added an import to the tlb file (had to add import to generated tlh file for IntelliSense to work)
#import "bin/MathLibrary.tlb"
using namespace MathLibrary;
And the following function is supposed to call the c# function
CoInitialize(NULL);
MathLibrary::IMathLibraryPtr IcalcPtr;
HRESULT hr = ::CoCreateInstance(__uuidof(MathLibrary::MathCalc), NULL,
CLSCTX_INPROC_SERVER,
__uuidof(MathLibrary::IMathLibrary),
(void**)&IcalcPtr);
_bstr_t calcVal;
if (FAILED(hr) || IcalcPtr == nullptr) {
// CoCreateInstance failed
// THIS CONDITION IS MET
(*resPointer)->Error("Cannot Create COM Object");
return;
}
//IcalcPtr->multiply(a, b, &calcVal);
calcVal = IcalcPtr->multiply(a, b);
// not sure how to convert bstr to std::string
const char* calcStr((const char*) calcVal.GetBSTR());
c.assign(calcStr);
CoUninitialize();
The CoCreateInstance fails.
Since I have no experience with c++, I am confused,
what is IMathLibraryPtr(I didn't define in c#)
Intellisense showed that a and b in IcalcPtr->multiply(a, b) are long but I thought it would be int
When I make a release build do I need to include the tlb or dll
what is tlh file, it got generated during build and I got Intellisense support only if I add an import to that file
I would like to understand in general how to interact with c# com-interface from c++ and also how to make it work in my case. Sample code and document links would be helpful
The problem was with the way the c# dll was built and not with the way it was called from c++. I had built the dll for "Any CPU" once I built it for x64 it worked.

co_await expression needs await_ready function

I have a Win32 programm, where I want to add some winRT calls. Among other things I want to open a file without a GUI interface.
I use the async file open call from the StorageFile class, because the next call needs an IStorageFile interface.
#include <roapi.h>
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.Foundation.h>
void openFile()
{
using namespace winrt;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Storage;
HRESULT rtn = RoInitialize(RO_INIT_MULTITHREADED);
winrt::hstring path{ L"C:\\Users...\\mytextfile.txt"};
//wait for open the file
auto file = co_await StorageFile::GetFileFromPathAsync(path);
//IStorageFile interface needed
}
int main()
{
openFile();
return 0;
}
At the moment, the compiler complains that the co_await expression requires a suitable "await_ready" function and none was found.
I`m not sure if this is the case due to a missing header include or if "co_await" can not be used within a win32 application.
Edit:
My visual studio project setup is:
- use c++17, add cppwinrt.exe to my include directories, link against windowsapp.lib and use windows sdk version 10.0.17134.0.
The problem is that the openFile() function does not have the proper return type to handle co_await.
See the research and work that went into the answer I created for C++11 threads to update MFC application windows. SendMessage(), PostMessage() required? which contains a list of recommendations for various approaches to coroutines.
This question was about using C++/WinRT with MFC but the material also applies with WinAPI.
See as well synchronizing SDK with Windows 10 update and using WinRT with Standard C++ which contains a simple console application example using the Web Syndication async functionality to retrieve a list of URLs from an RSS feed. There are a number of links to documentation, some of which is a bit out dated now.
Addendum: Sample Console application
I created the following simple console application using Visual Studio 2017. I created the text file and then ran this in the debugger. I then renamed the text file and ran it again in the debugger and an exception was thrown since the file with that name no longer existed.
See also C++/WinRT, part of Windows SDK 17134 is not compatible with Visual Studio 15.8 Preview 3 which describes a compiler option you may need to change. I did.
// console_winrt.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
// Requires the following changes to the project properties in the C++ compiler section.
// - C++ language standard must be set to C++17
// - Add /await to the Additional options
#include "pch.h"
#pragma comment(lib, "windowsapp")
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.Foundation.h>
#include <iostream>
winrt::Windows::Foundation::IAsyncAction openMyFile()
{
winrt::hstring path{ L"D:\\Users\\rickc\\mytextfile.txt" };
//wait for open the file
auto file = co_await winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path);
//IStorageFile interface needed
auto xDate = file.DateCreated();
std::cout << "file was found " << std::endl;
}
int main()
{
// initialize the WinRT apartment.
winrt::init_apartment();
auto x = openMyFile();
// wait on the file access since that is all we are doing and we need to give it time.
x.get();
return 0;
}
I used the following properties settings.

CLR (c++ .net) as Addin to Dynamic NAV

I think this might be more generic, but in this case I try to create a c++ CLR to Microsoft Dynamic NAV.
If I do this in C# it works fine. C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VisualCSharp
{
public class MyTest
{
public MyTest()
{
}
public int AddTest(int a, int b)
{
return a + b;
}
}
}
When I try to add that to Dynamic NAV, I find it:
Select and press OK:
So far so good.
Then I like to do the same in C++ with a CLR class.
I start with creating a C++ CLR Class library and add the code for the test: (I did it inline here, just to keep code simple, but it does not matter if I separate it.)
#pragma once
using namespace System;
namespace VisualCPP
{
public ref class MyTest
{
public:
MyTest()
{
};
int AddTest(int a, int b)
{
return a + b;
};
};
}
Do the same with this. In Assembly list it come up identical to the VisualCSharp addin, but it shows up as Processor "x86", but thats ok. I have C# that also do that (COM wrappers) and they also work fine.
However, when I press "OK" i do get an error telling me that it can not load the type "VisualCPP".
So, question is: What am I missing? I know that the CLR code is different as it is not pure managed (even using the depricated /pure compile option does not work), but is there some kind of setting or declaration that had to be done to make my class visible?
As far is I know you cannot use unmanaged code in NAV.
You assembly also need to be signed - in you example the Public Key Token is null therefore it's not gonna work.
Situations like that I always recommend to create a wrapper dll to handle the unmanaged code though it (for example this is what Microsoft was done with the Office SDK)
I hope it helps.
Cheers!

Integrate a COM object in a C++ CLR Console App

I am trying to use a COM object in a C++ CLR Console App as I did in C#. (it comes from statconn) I am new with the C++ CLR code and I don't find sample explaining how it works
I did the following things:
using namespace StatConnTools;
using namespace StatConnControls;
using namespace StatConnectorCommonLib;
using namespace STATCONNECTORSRVLib;
STATCONNECTORSRVLib::StatConnector^ oStatCon = gcnew STATCONNECTORSRVLib::StatConnector();
oStatCon::IStatConnector::Init(L"R");
oStatCon::IStatConnector::Close();
I get the message : oStatConn must be a class or namespace when followed by ::
thanks for help
The variable oStatCon is an object, i.e. an instance of a class. The scope operator can only be used on namespaces or classes, like the error message says.
You should be calling Init and Close as normal functions:
oStatCon.Init(L"R");
oStatCon.Close();

How to load a VC++ CLR library in MFC application?

HI I have a application developed in VC++6.0 ,now I want use some new features from .NET and developed a library, to develop this library I have to use the CLR-VC++ now I packaged this in a DLL.Now I need to call the routine of this DLL in my MFC application.
I tried to write a small MFC application to load this DLL, All the time the LoadLibrary() call is failing #err =126, module not found.I check the the dll with dependency walker everthig is fine there. Please Help me in this regard.
If possible provide me a sample code or link.
Thanks in advance
-Sachin
Use ClrCreateManagedInstance to create a COM-Callable-Wrapper for the object you want to call. Then use it like any other COM type.
you have to go to property page -> Common properties ->Add New reference and include you
CLR Address there .
I have a native C++ application which uses a managed C++ assembly and loads it with LoadLibrary() without problems. I had to do two things, however, before LoadLibrary() worked:
Make sure that the current directory is the one where the managed assembly resides (use chdir() to change directory)
In the managed assembly, the first function invoked by native code only defines the handler for AppDomain::CurrentDomain->AssemblyResolve event which explicitly loads assemblies from the folder of the managed application. It then invokes another managed function to do the rest of the initialization.
The reason for the last point is that CLR attempts to load an assembly dependency only if a function uses it. So I had to ensure that types in non-system assemblies are not referenced before the AssemblyResolve handler has been defined.
ref class AssemblyResolver
{
public:
/// The path where the assemblies are searched
property String^ Path
{
String^ get()
{ return path_; }
}
explicit AssemblyResolver(String^ path)
: path_(path)
{ /* Void */ }
Assembly^ ResolveHandler(Object^ sender, ResolveEventArgs^ args)
{
// The name passed here contains other information as well
String^ dll_name = args->Name->Substring(0, args->Name->IndexOf(','));
String^ path = System::IO::Path::Combine(path_, dll_name+".dll");
if ( File::Exists(path) )
return Assembly::LoadFile(path);
return nullptr;
}
private:
String^ path_;
};
extern "C" __declspec(dllexport) void Initialize()
{
String^ path = "The path where the managed code resides";
AssemblyResolver^ resolver = gcnew AssemblyResolver(path);
AppDomain::CurrentDomain->AssemblyResolve += gcnew ResolveEventHandler(
resolver,
&AssemblyResolver::ResolveHandler
);
FunctionWhichUsesOtherManagedTypes();
}