Hello Wilma,
You need to compile and link your entire application with winegcc (or wineg++) and run it through Wine. winegcc will give you a file app.exe.so, which you can run with "wine app.exe.so". It'll also create an app.exe shell script that invokes Wine for you.
The reason why you cannot simply dlopen a Wine DLL and call code from it is that Wine's DLLs depend on having a running wineserver instance to take care of Windows kernel tasks that do not exist on the Linux side, e.g. the registry. Furthermore dependencies between Wine DLLs are resolved via PE exports / imports, so when you dlopen crypt32.dll the required user32.dll, advapi32.dll and bcrypt.dll libs won't be loaded and linked.
A winelib-linked program can call link to and call any Linux shared library. If the Wine-dependent functionality is relatively small and you do not with to have all of Wine loaded whenever your program is running, you could consider making the Wine-dependent bits run in an external process and communicate via pipes, sockets or shared memory with your main program.
I hope this helps.
Stefan
Am 2018-08-30 um 13:00 schrieb Wilma Feuerstein:
I'm trying to call a winelib-function from a Linux C/C++ shared-library. The reason for it is, that I want to call some wine-dll-functions from C#.
I wrote a wineg++/winegcc compiled shared-library (libtest.c), which I want to call from a gcc/g++ main program (for testing).
Inside the shared library, I try to call CryptProtectData (in Crypt32.lib) and GetVersionEx (Kernel32.lib) - for a test - and just printf the results. Inside the main application, I dlopen the shared library, and dlsym the wrapper-function which calls CryptProtectData/GetVersionEx, then I try to execute that wrapper function.
But as soon as the execution hits the CryptProtectData/GetVersionEx, I get *Segmentation fault (core dumped)* .
Why ? The source-code for calling the CryptProtectData/GetVersionEx function works, tested it on Windows. Invoking a dlsym-ed function that doesn't call a wine-function works as well. But invoking a dlsym-ed function that calls a winelib-function does NOT work (segmentation fault). Do I need to call any undocumented wine init-code ? Or what is the problem ? Can I even run libtest.dll.so inside an application that isn't run with wine / that isn't compiled with wineg++ ? If the latter is the case, is there some hack somewhere to make it work ? Basically all such a hack would need to do is loading some libraries, and execute some init code, or not ?
|wineg++-m64 -shared -fPIC -Wall-lrt -ldl -lpthread -lwine -lmsvcrt -lcrypt32 -lusp10 -o libtest.so libtest.c g++-m64 app.c -ldl -o app ./app|
Details/Code here: https://stackoverflow.com/questions/52093440/how-to-call-wine-dll-functions-...
Am 30.08.2018 um 23:56 schrieb Wilma Feuerstein officedev@gmx.ch:
I'll have to think about whether it might be easer ripping the respective code out of wine.
You can try, but my guess is that you'll run into calls to lower-level Wine functions that will cause you the same pain as dlopen does.
Writing a socket server for ~100 APIs with byref-arguments, with C and Windows-size datatypes on one side, and C# on Linux on the other, where the C# code runs inside a web-server, seems like a daunting task that might be more complex than writing a basic web server.
You don't necessarily have to marshall the Win32 API. Do you have any internal APIs in your software (e.g. between your host process and a plugin) that is smaller?
Is it not somehow possible to load the wine-server process inside the libtest.dll.so-constructor ? #define LINUX_ATTACH_DLL __attribute__((constructor)) whether that server process would be started inside the same process or outside wouldn't matter much.
I don't know for sure. You could read through Wine's init code in loader/main.c, libwine and ntdll and see if you can reconstruct it elsewhere. It is certainly not a simple task.
If I had to manually dlopen the dependencies between crypt32.dll, user32.dll, advapi32.dll and bcrypt.dll - and whatever - in the right order, that's something I could live with.
The problem isn't just loading the libraries, you also have to resolve the imports. You might be able to dlopen ntdll.dll and then use LdrLoadDll to load the higher level DLLs.
But just looking at the first lines of LdrLoadDll brings up a call to NtCurrentTeb(), which will return NULL unless you also call the right ntdll init code.
I don't understand. If you're P/Invoking Win32 DLLs, why don't you just run your .NET program in Wine in the first place?
September 6, 2018 7:01 AM, "Wilma Feuerstein" <officedev@gmx.ch (mailto:%22Wilma%20Feuerstein%22%20officedev@gmx.ch)> wrote: Thanks, but no, it doesn't come any smaller - the 100 API calls is the internal API. Poking through the wine code, I've come to the same conclusion in the meantime. Not modular and not reusable. I'm still a bit alienated, as I think others have to have had the same problem before. But I guess it's just not a planned/intended use case. Well then wine/winelib as such is useless for me. Wine has non-the-less been useful, as I can look at the source of the functions, and determine what they actually do. Have managed to replace 2 COM-calls already. I'm just going to have to use a C#-Freetype-wrapper to copycat the textmetrics struct initialzation and all the code around in C#. usp10# with a little gdi32# so to say. Gesendet: Dienstag, 04. September 2018 um 03:13 Uhr Von: "Stefan Dösinger" <stefandoesinger@gmail.com (mailto:stefandoesinger@gmail.com)> An: "Wilma Feuerstein" <officedev@gmx.ch (mailto:officedev@gmx.ch)> Cc: wine-devel@winehq.org (mailto:wine-devel@winehq.org) Betreff: Re: Possible to call winlib function from native program ? Am 30.08.2018 um 23:56 schrieb Wilma Feuerstein <officedev@gmx.ch (mailto:officedev@gmx.ch)>: I'll have to think about whether it might be easer ripping the respective code out of wine. You can try, but my guess is that you'll run into calls to lower-level Wine functions that will cause you the same pain as dlopen does. Writing a socket server for ~100 APIs with byref-arguments, with C and Windows-size datatypes on one side, and C# on Linux on the other, where the C# code runs inside a web-server, seems like a daunting task that might be more complex than writing a basic web server.You don't necessarily have to marshall the Win32 API. Do you have any internal APIs in your software (e.g. between your host process and a plugin) that is smaller? Is it not somehow possible to load the wine-server process inside the libtest.dll.so-constructor ? #define LINUX_ATTACH_DLL __attribute__((constructor)) whether that server process would be started inside the same process or outside wouldn't matter much. I don't know for sure. You could read through Wine's init code in loader/main.c, libwine and ntdll and see if you can reconstruct it elsewhere. It is certainly not a simple task. If I had to manually dlopen the dependencies between crypt32.dll, user32.dll, advapi32.dll and bcrypt.dll - and whatever - in the right order, that's something I could live with. The problem isn't just loading the libraries, you also have to resolve the imports. You might be able to dlopen ntdll.dll and then use LdrLoadDll to load the higher level DLLs. But just looking at the first lines of LdrLoadDll brings up a call to NtCurrentTeb(), which will return NULL unless you also call the right ntdll init code. Chip