I'm trying to use native C++ libraries in a MAUI app and cannot get it working for MacOS/iOS - c++

There's a great article here that describes how to use native C++ libraries in Xamarin/C#, and I would assume that this would extend to MAUI: https://learn.microsoft.com/en-us/xamarin/cross-platform/cpp/
I followed these instructions, and put together an end-to-end demo solution of it here: https://github.com/whodges/bindingsample. This does require that you link Visual Studio to a MacBook to build the full solution.
That example essentially uses the default MAUI template, and modifies it slightly so that the actual 'click counter' value is set and retrieved from a native library on a per-platform basis. For Windows, that's a C++ DLL (works great). For Android, that's a .so library (works great). And for iOS, that's a static .a library, and here's where I'm running into trouble: when I try to launch this app using the iOS Simulator, it fails with a clang++ error, and something along the lines of "Could not extract the native library 'libCounteriOS.a' from .../obj/Debug/net6.0-ios/iossimulator-x64/linker-cache/libCounteriOS.a'. Please ensure the native library was properly embedded in the managed assembly (if the assembly was built using a binding project, the native library must be included in the project, and its Build Action must be 'ObjcBindingNativeLibrary')".
I created a C# .NET iOS Binding Library project (Counter.iOS in my example), and this is supposed to bundle libCounteriOS.a, which is generated when CounteriOS (a C++ project) is compiled. First, when Counter.iOS is built using Visual Studio on Windows, it fails to generate the Counter.resources folder in its 'bin' folder, along with the subsequent 'manifest' file. When I use Visual Studio for Mac, these files do get generated. So, I stuck with Visual Studio for Mac to build the iOS.Counter project (everything else is built with Visual Studio on Windows).
Regardless, I still get the "could not extract the native library" error I described. I've tried setting the library file's Build Action in Counter.iOS to ObjcBindingNativeLibrary, but that just results in an unhelpful "Build failed - see build log for details" error in Visual Studio for Mac, and I cannot find said log file for the life of me. On top of that, it's not an Objective C library anyway - it's a C++ one - so I'm not sure if this step is actually appropriate. Does it have to be Objective C? The Xamarin article suggests otherwise, and the native reference option 'Is C++' is there as well. I've also tried setting libCounteriOS.a's Build Action to 'BundleResource' - no luck with that either. I've tried it with .NET 7.0 as well - also no luck there.
I'm really at a loss. Is this even possible? It doesn't seem to work and I've been poking at it for weeks on it. That Xamarin article seems to suggest it should be possible. Any help would be greatly appreciated.

Related

Bad image format when running managed C++/CLI assembly in .NET Core 3.1

I was super excited to see that the latest previews of .NET Core 3.1 and Visual Studio 2019 add support for managed C++/CLI projects, as such a project is the only think keeping a particular project on .NET Framework.
So, I installed Visual Studio Preview 16.4.0 Preview 4, along with the "C++/CLI support for v142..." options, and as expected I see the new C++ CLR templates and have .NET Core 3.1 preview 2 installed
I created a new project using the "CLR Class Library (.NET Core)" template, copied the files an old managed C++/CLI project, tweaked a little, and the assembly built - great!
However, when I try to use the assembly in a .NET Core 3.1, I get this fatal exception:
Unhandled exception. System.BadImageFormatException: Could not load file or assembly 'MyAssembly, Version=2019.0.1.0, Culture=neutral, PublicKeyToken=null'. An attempt was made to load a program with an incorrect format.
File name: 'MyAssembly, Version=2019.0.1.0, Culture=neutral, PublicKeyToken=null'
at TestApp.Program.Main(String[] args)
Both the managed assembly and test app target X64. Any ideas what could be the problem?
Someone from Microsoft provided the solution over on the Github repo.
When the managed C++/CLI project is built, a file ijwhost.dll is placed in the output folder alongside the assembly - this file needs to be deployed with the app that uses the assembly.
After putting ijwhost.dll in the same folder as the app, it worked as expected.
As an aside, the old C++/CLI project that I built against .NET Core 3.1 preview is actually quite complex - I'm very pleasantly surprised that it basically "just worked"!
Hopefully a better error message will be used in future!
I am using .net 5.0 as the CLI runtime. I finally found that the problem I have is missing native dependency DLLs.
For native applications, there will be an error prompt telling you which DLL is missing. While in .net core C++/CLI, they only give you a BadImageFormatException.
My solution is, create a pure native console project, paste the code that will cause BadImageFormatException, run it and see which DLL is missing then add it back to C++/CLI project file list.
I just found some unexpected dependencies.
In my case c# Net 5.0 app loads managed C++ dll, which is wrapping around unmanaged C++ dll.I get this error every time i try to run on on machine with no Visual Studio installed. I debugged it with ProcessMonitor and figure out that it can't found VCRUNTIME140D.dll. Found these dlls in my dev PC, copied them (both 32 and 64 bit versions) from my dev machine to customer's one to corresponded folders, and it made the trick. Hope will help somebody. Cheers.

Trouble getting a (stripped) DLL to work with a C++ console app

I have a project to make an oldish (stripped, non-Com) DLL work in a new C++ console app. I've tried several things:
Import a new reference from the Visual Studio console ... this doesn't work (apparently) because it's a non-COM thing ... 'browse' shows nothing in both Visual Studio 2017 and 2019.
use dumpbin and lib to create a lib from the DLL; dumpbin worked but lib gets a bunch of warnings:
LNK4017: statement not supported for the target platform: ignored
... and produces an apparently blank library.
Tried cygwin tools ... which don't work with stripped DLLs but otherwise look lovely ...
Questions:
Is this a waste of time? The vendor is supporting C# exclusively these days but the guy I'm working with is a C++ guy from way back and wants this if it's doable.
If there's some easy way to do this, what is it please? I'm fully Linux/Cygwin/Msys2 capable if some of those toolkits will do this. I've been working for several hours on this today already.
Thanks much ...

building curl 7.46.0 on windows without cmd

curl being new to me, I am figuring out an easier way to compile it on Windows. I've managed to find a good documentation explaining in layman's terms all the steps, however this doc is based on curl-7.9.6.
It was simpler since curllib.dsw which is the Visual Studio Project file for curllib was found in folder curl-7.9.6\lib. So building it was resulting in libcurl.dll + libcurl.lib
Unfortunately this project file is no more in the latest version 7.46.0, and I would not like to mess around using other techniques I am not familiar with, compiler other than msvc (e.g MinGw), and if possible without resorting to cmd.
I have already done some researches online before posting this thread, but we never know maybe someone has written on this topic very simple documentation that everyone could understand and willing to share it publicly to get both the static library file and DLL (raised just above) or have found a way to get back the project file (.dsw) in the latest release which will a priori be straightforward to compile using Visual Studio 2013 (v120)
Best

Building ActiveQt (COM) applications with MinGW

I am using Qt 4.6.3 with MinGW on Windows to build Qt apps and now need to add a COM interface to my application. I enabled ActiveQt but was getting post-link errors because I was missing a copy of the MIDL compiler. I downloaded a copy of the latest MS Windows SDK, which includes MIDL, but now MIDL complains it cannot find cl.exe. The only conclusion I can draw is that you can only build ActiveQt applications using the MS compiler, which I would rather avoid. Is a way to get this working with MinGW or am I out of luck?
Using the MS compiler and tools seems to be the only reliable way to get this working.
Well, you can build ActiveQt with MinGW, but using a bunch of COM stuff on top of that may not be possible, because it may or may not be present in MinGW. Some thoughts:
Using any MS SDK tools with MinGW won't work (exception is mingw.org + DXSDK which should work most of the time).
Are you sure you are linking all necessary libraries when compiling? I can't help more if you don't show the exact error messages.
The mingw-w32/w64 project tries to provide a completer "Windows SDK for GCC"; it may contain the libraries/files you are looking for. They provide a x64 and x86 compiler, and pretty good DX support. I have no experience with their COM stuff, but I believe it would be a bit more complete than mingw.org's. You can always contact the developers on the forums or mailing list, they are very helpful.
You could try the Wine implementation of midl, widl. See the Wine wiki page regarding building on Windows.
If you want to give it a quick run, get wine-prgs-0.9.14-mingw.zip and see how it works.
I agree with Rob's second post: it's a very bad thing using mingw for construction of ActiveX objects. Mingw has some bugs regarding ActiveX: https://bugzilla.mozilla.org/show_bug.cgi?id=203299 and also: https://qt.gitorious.org/qt/qt/merge_requests/2710. I kill the whole day to discover it. Use Qt for MSVS instead and all will be ok. ;)
I've solved this problem next way:
Got QtCreator, Msys2 and VS2015 Community installed.
Launching Qt Creator with batch script:
#echo off
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86 8.1
setlocal
set MSYSTEM=MINGW32
set MSYS2_PATH_TYPE=inherit
start "" "C:\msys64\usr\bin\mintty" -i /msys2.ico -e /usr/bin/bash --login -c "/c/Qt/Tools/QtCreator/bin/qtcreator.exe"
exit /b 0
I am launching QtCreator out of Msys2 envioronment because it provides standart Unix tools needed to build 3rd party in my project.
So in theory this is not mandatory to have Msys2 for you.
Please note: do not use WinSDK 10.0 (or above) because it does not have midl.exe in PATH variable.
Doing this way will create PATH environment variable with Qt Creator on top priority (so you will use gcc from Qt installation), Msys2 next (so you can use standard Unix tools) and MSVC and WinSDK 8.1 at last place (so while building you will find midl compiler).
Right now I succeed building dll and passed it to midl form WinSDK, but as for now I am stil trying to register it in system.
I did actually succeed in creating and invoking in-process and out-of-process servers using QT+mingw-w64 today, so here is a write-up.
This was based on the instructions at https://doc.qt.io/qt-5/activeqt-server.html , although they were written for the Windows-native build of QT and using MSVC, so some changes were needed .
Tools installed
MSYS2 updated to latest version (as of 29 Oct 2020).
qtcreator and mingw64/mingw-w64 (64-bit target), installed via MSYS2.
Package mingw64/mingw-w64-x86_64-qt5-static installed (this causes the "Qt5 Static" kits in qtcreator to be enabled).
Visual Studio 2019 Community edition (this provides midl.exe).
https://github.com/lucasg/Dependencies - lucasg Dependencies walker. (Not essential but good for checking your static build worked).
Creating the COM DLL (without a type library yet)
These steps assume prior familiarity with QtCreator+qmake for "normal" executables.
Copy the example project from qtactiveqt/examples/activeqt/simple . I actually couldn't find this anywhere in the MSYS2 installation of QT so I cloned the QT source directly and picked out the example.
In the Kit Management in QtCreator, I selected the qt5-static 64-bit kit. This is to avoid any issues due to DLLs not being found at runtime.
This example is an out-of-process server, so to change to in-process, add to the simple.pro file the lines: TEMPLATE=lib and CONFIG += dll.
Enable static linking in GCC as I describe in this answer: https://stackoverflow.com/a/64583309/1505939
Build the project . This will give a warning that it couldn't read simple_res.o but that can be ignored. This should successfully create the output file simpleax.dll, but then there are some error messages to do with widl not found -- which we will address in the next section.
Writing the type library to the DLL
Other Windows tools (e.g. regsvr32, and any other client who wants to use the DLL) expects to be able to read the type library out of the DLL.
The DLL which was created in the previous steps does not contain a type library. I think this is because none of our toolchain tools know how to create a type library. Instead, we have to use midl.exe supplied with VS Community to generate the type library.
In QtCreator there is a post-build script that's supposed to invoke midl . However that doesn't work in the MSYS2 flavour of QtCreator. It seems it was only written for the native flavour using MSVC as the kit.
So we have to manually do the post-processing, which involves:
In the MSYS2 shell, go to the directory of simpleax.dll.
Run this command: idc simpleax.dll -idl simpleax.idl -version 1.0
Start the "x64 Native Tools Command Prompt" start menu item that came with the VS Community installation.
Navigate to the directory of simpleax.dll
Run the command: midl simpleax.idl /nologo /tlb simpleax.tlb. (Note - just adding midl to the MSYS2 path doesn't work as it can't then find a bunch of other dependencies).
Back in the MSYS2 shell, go idc simpleax.dll -tlb simpleax.tlb.
Note that you only need to do all this if the type library changes (i.e. you make a change to the class definition of your exported COM objects). If just rebuilding the project then only the last step would be needed, which you probably can add as a manual build step in the QtCreator config.
Registration and run test
Congratulations! You should now be able to open an elevated command prompt and run regsvr32 simpleax.dll and have it succeed. (If it doesn't work, run dependencies -chain simpleax.tlb and then at the end it will list any DLL dependencies).
After registration succeeded, I was able to invoke the COM object using VS Community (New C++ Console project, and #import "D:\path\to\simpleax.dll", build, and then it creates a .tlh C++ header file that contains wrappers for the DLL).
Cleaning up the type library
The type library that was created contains a whole bunch of annoying QT guff. I discovered that if you want to create a COM object that's not an ActiveX control, you can use QObject instead of QWidget as the base class. Then you don't get most of the guff that is to do with GUI elements.
Also, taking out the Q_CLASSINFO("EventsID",... line from the COM object's class definition means you don't get all the source/sink guff in the type library (for some reason it decides it has to put all the QT event sinking stuff in there).
After doing that, there is only about one screenful of guff left, including the definition of QPoint and so on, that I would consider to be a bug on the part of QT (since the stuff is not needed). I found I could just remove that from the .idl file prior to invoking midl, and hey presto we have a clean interface that can be published.
The out-of-process server
This also worked for me, identical to the above steps but without step 3 (i.e. leave it as app instead of lib). The procedure for attaching the type library via midl is the same.
Registering the type library via testobject.exe -regserver gives no message to tell you if it succeeded or failed, so another way is to use idc -regserver testobject.exe from elevated MSYS2 prompt, then it will give you a failure message.
I was able to invoke the object via VS Community just the same as for the in-process server.
Further issues still to work out
Figure out how to do this in CMake.
Automate the post-build type library procedure.
Get non-static linking working.
Automate removal of the type library guff (or report a bug)

wxWidgets running on other machine

I created application which uses wxWidgets library using visual studio 2008. Now I would like to create version which may be run on other machine.
Because right now when I want to run It on another machine there is an error:
the application failed to start because its side-by-side configuration is incorrect.
What can I do to make It work ?
The Event Viewer should have a record showing what DLL was being searched for, what version of that DLL if found in the SxS cache, and what version it was looking for but couldn't find. You'll then want to (for example) include the correct version of that DLL to be installed with your program. Alternatively, just link to virtually everything statically -- it'll make your executable a lot bigger, but eliminate a lot of problems like this relatively painlessly.