I am trying to use an AppService in winrt/c++, following the github sample in C++/Cx. I always get the "AppUnavailable" result. I have confirmed I connect to the correct service name and have the correct family package name.
My appxmanifest:
<Extensions>
<uap:Extension Category="windows.appService" EntryPoint="BlankApp5.Inventory">
<uap3:AppService Name="com.microsoft.inventory" uap4:SupportsMultipleInstances="true"/>
</uap:Extension>
</Extensions>
My provider header file (in Mainpage.h):
namespace winrt::BlankApp5::implementation
{
class Inventory : public InventoryT<Inventory> {
public:
virtual void Run(IBackgroundTaskInstance taskInstance);
private:
BackgroundTaskDeferral mDef;
AppServiceConnection appServiceConnection;
};
My MainPage.idl file:
[default_interface]
runtimeclass Inventory : Windows.ApplicationModel.Background.IBackgroundTask
{
void Run(Windows.ApplicationModel.Background.IBackgroundTaskInstance taskInstance);
}
During IDL generation I get the following warning:
[msg]A member name has been qualified with an interface name because name collisions occurred across interface members on a runtime class. [context]"Run" has been renamed as "BlankApp5.IInventory.Run" on runtime class "BlankApp5.Inventory"
I am a bit worried that the Inventory::Run gets stripped by the linker, as it is not used internally in the serviceprovider, but I have no other idea why it doesnt work. The provider and client are in two different solutions and have no references between each other, but I assume this is not needed. The service prodiver has been deployed, but not launched. Launching makes no difference.
You needn't declare the void Run(Windows.ApplicationModel.Background.IBackgroundTaskInstance taskInstance); in your idl file, because you implement IBackgroundTask and a void Run is declared implicitly.
Related
First i try to explain the story.
I wanted to extend an C++/MFC application with REST-APIs, and decided to use for this purpose Asp.Net-Core 5 in a library by bridging it to unmanaged code with C++/CLI library. (having a separete ASP application is doubled expenditure, and needed to be rewritten all the logic in C#. in that regard RESTful-Server should be in same process implemented.)
Asp-Host is started in that way; C++/MFC -> C++/CLI -> ASP-Library (ASP referenced in CLI, CLI referenced in Native)
First problem was; by building the host Microsoft.Extensions.Hosting.Abstractions-Assembly could not be resolved. I found that, "My CLI Library".runtimeconfig.json has wrong framework reference and causes it not to be resolved. That means generated runtimeconfig.json is wrong. After every build it has to be manually with AspNetCore instead of NETCore corrected. (Done in PostBuildEvent)
Next problem; during the ASP-Host build, ASP could not resolve "My ASP Library.dll"-Assembly (in reflection). This problem solved by OnAssemblyResolve event by giving the right path. I'm not sure whether it is correct solution. Because AppDomain.BaseDirectory is an empty string, maybe it is the cause of it, that the library could not found.
In AssemblyResolve event;
Assembly::LoadFrom(assemblyFile)
Finally i could start the server, and it works. Then needed to use dependency injection, and my service could not be resolved from the controller.
Then i used my ASP-Library in another C#-project to test and it works...
i'm sure that it doesn't work if the entry point of process is in unmanaged code.
public interface IServerImpl
{
void OnFail(String msg);
}
public class CServerImpl : IServerImpl
{
public void OnFail(String msg)
{
}
}
... in Startup
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IServerImpl, CServerImpl>();
services.AddControllers();
}
... Controller
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
private readonly IServerImpl _serverImpl;
public WeatherForecastController(ILogger<WeatherForecastController> logger, IServerImpl serverImpl)
{
_logger = logger;
_serverImpl = serverImpl;
}
...
}
Is there any workaround to have it working? Are those problems bug in Asp.Net-Core or what am i doing wrong?
Thanks in advance
The problem has been solved. Assembly resolving event with Assembly.LoadFrom() causes my ASP-assembly to be loaded (or mapped) twice. Loading it in different assembly-load-context means that, doubled Types, static variables and so on. In that regard my registered IServerImpl service searched in the controller with another IServerImpl type. Type names are identical, but not the same.
For more information see technical challenges: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.loader.assemblyloadcontext?view=net-5.0
Another issue on GitHub: https://github.com/dotnet/runtime/issues/39783
In assembly resolve event, i'm returning now the loaded assembly like that, instead of loading it again;
AppDomain.CurrentDomain.GetAssemblies()
.SingleOrDefault(asm => asm.FullName.StartsWith(args.Name.Split(',')[0] + ","))
still wellcome answers which clarifies "why my ASP-assembly not found from the framework?"
Following the tutorial I successfully generated the code I expected with protocol buffers:
protoc service.proto --proto_path="../proto/" --cpp_out="../cxx/gen/" --plugin=protoc-gen-grpc=`which grpc_cpp_plugin`
The models are generated as usable classes without error, but the service implementation differs from the one described in the above tutorial. The proto file looks like this:
syntax = "proto3";
option cc_enable_arenas = true;
option cc_generic_services = true;
package my_package;
message Service_slot{...}
message Slot_status{...}
message Slot_request{...}
message Service_slot{...}
service My_service{
rpc add_slot(Service_slot) returns (Slot_status) {}
rpc update_slot(Service_slot) returns (Slot_status) {}
rpc request_action(Slot_request) returns (Slot_status) {}
}
What I could identify as a service looks like this(in service.pb.h):
class My_service: public ::google::protobuf::Service {
protected:
// This class should be treated as an abstract interface.
inline My_service() {};
public:
virtual ~My_service();
typedef My_service_Stub Stub;
static const ::google::protobuf::ServiceDescriptor* descriptor();
virtual void add_slot(::google::protobuf::RpcController* controller,
const ::my_package::Service_slot* request,
::my_package::Slot_status* response,
::google::protobuf::Closure* done);
//... (others left out for clairty)
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(My_service);
};
but it's nothing like what' described in the tutorial. Not even sure how to provide those arguments.
I've done this in Java, and there the server I implemented was based on a classname ending with grpc, but I found nothing like this here.
What have I found, and how can I understand it? I believe this must be a base service implementation, and the actual server I need to implement is not here.
Maybe I generated the proto files wrong? What can I do to correct it?
I was missing the --grpc_out="../cxx/gen" argument.
With the command
protoc service.proto --proto_path="../proto/" --cpp_out="../cxx/gen/" --grpc_out="../cxx/gen --plugin=protoc-gen-grpc=`which grpc_cpp_plugin`
The service code now generates into the service.grpc.pb.cc file.
I am currently developing on a Chromium Embedded framework app.
The project consists of a client and a helper. I need to know the bundle path from the helper, easy just use the methods of foundation.... Well I can't since I can't use foundation in the helper.
The client is a C++ based core wrapped in a objective-c++ cocoa app.
The helper is pure C++.
The two apps share an custom class for process-type-based behaviour ( see code below). The "OnBeforeCommandLineProcessing" method needs to use the bundle path! (Just changing file ending to .mm and importing foundation/cocoa does not work, as soon as i import foundation things turn ugly with a huge amount of errors). How can I get bundle path from C++ without foundation? This does not work: mainBundle = CFBundleGetMainBundle();
namespace client {
// Base class for customizing process-type-based behavior.
class ClientApp : public CefApp {
public:
ClientApp();
enum ProcessType {
BrowserProcess,
RendererProcess,
ZygoteProcess,
OtherProcess,
};
// Determine the process type based on command-line arguments.
static ProcessType GetProcessType(CefRefPtr<CefCommandLine> command_line);
protected:
// Schemes that will be registered with the global cookie manager.
std::vector<CefString> cookieable_schemes_;
private:
// Registers custom schemes. Implemented by cefclient in
// client_app_delegates_common.cc
static void RegisterCustomSchemes(CefRefPtr<CefSchemeRegistrar> registrar,
std::vector<CefString>& cookiable_schemes);
void OnBeforeCommandLineProcessing(const CefString& process_type,
CefRefPtr<CefCommandLine> command_line) OVERRIDE;
// CefApp methods.
void OnRegisterCustomSchemes(
CefRefPtr<CefSchemeRegistrar> registrar) OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(ClientApp);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_COMMON_CLIENT_APP_H_
Trying to import cocoa/foundation after renaming to .mm:
You're importing Foundation.h when you mean #include <CoreFoundation/CoreFoundation.h>. Foundation is an ObjC API (which is not compatible with C++). Core Foundation is a C API. When you include CoreFoundation, CFBundleGetMainBundle() should be fine. Note the CF at the start that is indicating it's part of Core Foundation, vs NS which indicates Foundation (or AppKit).
There is no need to rename this .mm. As long as you use CoreFoundation, it's fine to be a pure C++ file. Just remember that Core Foundation has its own memory management. There is no ARC. You need to remember to CFRelease anything you obtained using a function with Create or Copy in its name (or that you called CFRetain on. Full details are in the Memory Management Programming Guide for Core Foundation.
The problem i am facing is...during the installation of my WMI application (which has obfuscated dlls) below error is shown:
Incorrect usage of [ManagementBind] attribute on a method. 'a' on class 'ak' (ak, Myapp.MyProvider, Version=1.3.0.11, Culture=neutral, PublicKeyToken=213fdfdfdf32dfef) definition. It should be on a static method and there should be one matching parameter for every key defined. "
Please let me know how to resolve this error.
It does not sounds logical to obfuscate everything in your WMI provider. Since the metadata (like the names of methods, parameters and classes) describes how your WMI provider looks at the outside. Do you want the users your WMI provider to have a WMI class named ak? And a WMI method named a? I would rather have a MySomethingProvider with a GetInstances method.
But even if you want your users having to deal with obfuscated names, I think this obfuscation does not go well with how the metadata of a Managed WMI Provider should look.
For example, here the ManagementName attribute points to ID, but I bet that obfuscating it will have given ID another name. That is why they don't match
[ManagementBind]
static public WIN32ServiceHost GetInstance([ManagementName("ID")] int processId)
{
}
[ManagementKey]
public int ID
After obfuscation string in ManagementName is still ID, but now the property ID is called A.
[ManagementBind]
static public WIN32ServiceHost a([ManagementName("ID")] int a)
{
}
[ManagementKey]
public int A
So either don't obfuscate at all or only the parts that are not public or are part of your WMI API.
I have been going through links on StackOverflow on how to resolve the Method name mangling but did not find any solution with a real time example.
Scenario-A C++ Ex.dll file is provided by client. I need to access the Ex.dll and call the methods in the same through Java.
Restrictions- Cannot modify the Ex.dll, i can only access the same.
Issue Faced- Getting the below exception when i access the Ex.dll through JNA
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'getCPUSpeed': The specified procedure could not be found.
at com.sun.jna.Function.<init>(Function.java:134)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:336)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:316)
at com.sun.jna.Library$Handler.invoke(Library.java:203)
at $Proxy0.getCPUSpeed(Unknown Source)
at cpp.java.JnaTest.main(JnaTest.java:16)
Googled a lot and found that its due to method name Mangling, but again could not find any good sample code with the solution.
This is code i used-
import com.sun.jna.Native;
class JnaTest
{
public static void main(String args[])
{
try
{
JnaInterface jInterface = (JnaInterface) Native.loadLibrary("Ex", JnaInterface.class);
System.out.println("Calling C++ DLL method");
System.out.println("========================");
System.out.println("getCPUSpeed() -- "+jInterface.getCPUSpeed());
} catch (Exception e) {
e.printStackTrace();
}
}
}
package cpp.java;
import com.sun.jna.Library;
public interface JnaInterface extends Library{
public int getCPUSpeed();
}
Update 1: **************************************
Below mentioned is the actual functions i get when i browse the DBMM.dll through dependency walker-
DBMM DLL functions-
??0cDbmmInterfaceCache##QAE#ABV0##Z
??0cDbmmInterfaceCache##QAE#XZ
??0cDbmmInterfaceControl##QAE#ABV0##Z
??0cDbmmInterfaceControl##QAE#XZ
??0cDbmmInterfaceEcon##QAE#ABV0##Z
??0cDbmmInterfaceEcon##QAE#XZ
??0cDbmmInterfaceKnob##QAE#XZ
??0cDbmmInterfaceOutput##QAE#ABV0##Z
??0cDbmmInterfaceOutput##QAE#H#Z
??0cDbmmInterfacePoolLoan##QAE#ABV0##Z
??0cDbmmInterfacePoolLoan##QAE#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###Z
??0cDbmmMacroEcon##QAE#ABV0##Z
??0cDbmmMacroEcon##QAE#ABVcDbmmInterfaceEcon##_N#Z
??0cDbmmMtgBasisConstSpreadModel##IAE#XZ
??0cDbmmMtgBasisConstSpreadModel##QAE#ABV0##Z
??0cDbmmMtgBasisConstSpreadModel##QAE#PBD#Z
??0cDbmmMtgBasisModel##QAE#ABV0##Z
??0cDbmmMtgBasisModel##QAE#XZ
??0cScaleFieldsSubSum##QAE#NN#Z
??1cDbmmInterfaceCache##QAE#XZ
??1cDbmmInterfaceControl##QAE#XZ
??1cDbmmInterfaceEcon##QAE#XZ
??1cDbmmInterfaceKnob##QAE#XZ
??1cDbmmInterfaceOutput##QAE#XZ
??1cDbmmInterfacePoolLoan##QAE#XZ
??1cDbmmMacroEcon##QAE#XZ
??1cDbmmMtgBasisConstSpreadModel##UAE#XZ
??1cDbmmMtgBasisModel##UAE#XZ
??1cScaleFieldsSubSum##QAE#XZ
??4cDbmmInterface##QAEAAV0#ABV0##Z
??4cDbmmInterfaceCache##QAEAAV0#ABV0##Z
??4cDbmmInterfaceControl##QAEAAV0#ABV0##Z
??4cDbmmInterfaceEcon##QAEAAV0#ABV0##Z
??4cDbmmInterfaceKnob##QAEAAV0#ABV0##Z
??4cDbmmInterfaceOutput##QAEAAV0#ABV0##Z
??4cDbmmInterfacePoolLoan##QAEAAV0#ABV0##Z
??4cDbmmMacroEcon##QAEAAV0#ABV0##Z
??4cDbmmMtgBasisConstSpreadModel##QAEAAV0#ABV0##Z
??4cDbmmMtgBasisModel##QAEAAV0#ABV0##Z
??4cScaleFieldsSubSum##QAEAAV0#ABV0##Z
??_7cDbmmMtgBasisConstSpreadModel##6B#
??_7cDbmmMtgBasisModel##6B#
??_FcDbmmInterfaceOutput##QAEXXZ
??_FcDbmmInterfacePoolLoan##QAEXXZ
??_FcScaleFieldsSubSum##QAEXXZ
?Add#cScaleFieldsSubSum##QAEXNN#Z
?InitSubsum#cScaleFieldsSubSum##QAEXNN#Z
?ReInit#cDbmmMacroEcon##QAEX_N#Z
Not sure how can i call these functions through Java.
Appreciate if somebody could provide me a solution from Java end, with a sample code please :)
Your function is decorated with JNI and stdcall conventions; it is not C++-mangled.
It looks like the library is a JNI library, given the Java_sysInfo_ prefix. If that is the case, you need only declare the equivalent Java-side, e.g.
// default package
public class sysInfo {
static { System.loadLibrary("Ex"); }
public static native int getCPUSpeed();
}
I think you'll probably find that this mapping is the correct one and that you don't need JNA.
EDIT
Given a C++ class with an arbitrary ctor input argument and method getCount():
extern "C" int getCountForName(const char* name) {
MyCPPClass mycpp(name);
return mycpp.getCount();
}
Compile that into a shared library, and load via JNA.
If your building the DLL through Visual studio, you should be able to build it as a release instead of debug to fix the function names if you are not already doing this.