GPGME DLL questions

I’m one of the maintainers of gpgme-sharp, a library that provides GPGME bindings for C#. I had a few questions about the GPGME DLL:

  • I noticed a DLL at C:\Program Files (x86)\Gpg4win\bin_64\libgpgme6-11.dll that seems to be undocumented. This appears to be a 64-bit version of libgpgme-11.dll. Does the 6 in the name just signify that it’s 64-bit, or is there a deeper meaning there?
    • Which version of Gpg4Win added this DLL (since I don’t remember it being there in the past)?
  • Does the Gpg4Win installer write a registry key (or other configuration entry) with the path to Gpg4Win (e.g. C:\Program Files (x86)\Gpg4win\) that we can use to locate the DLLs if they’re not in the default location of %ProgramFiles(x86)\Gpg4Win\?
  • Would I be allowed to bundle libgpgme-11.dll and libgpgme6-11.dll with gpgme-sharp, or do I need to require that users install Gpg4Win manually (which is the current state today)? On Linux we just rely on libgpgme.so.11 being present on the system.

Thanks!

Hi Dan, welcome to our forum and thanks for developing a gpgme wrapper!

Good questions,
for some of your questions I do not know the answer, if you do not get one here, a good other place to ask is The Gpg4win-devel Archives or The Gnupg-devel Archives

Would I be allowed to bundle libgpgme-11.dll and libgpgme6-11.dll with gpgme-sharp,

It is possible if the conditions of the Free Software licenses are fulfilled. GPGME is under LGPL-2.1-or-later and GnuPG itself, which you would also need is under GPL-3.0-or-later.

While it is possible from the licensing side, it maybe better for updating if the original Gpg4win packages were used.

Regards,
Bernhard

Hello,

I have a question about the libgpgme6-11.dll file. I’m not sure if it is a 64-bit version, because when I try to link it from x64, I get a warning that x86 is not compatible with x64.

Also, I noticed that the LibGpgError file does not have the same extension as 6-11.dll.

Could you please explain how you managed to link it correctly? I would appreciate your help.

I have also posted this issue on the forum (with a link to working x86 CMakeList, and a project of c++ RAII wrap for this library we can test on):

I’m using P/Invoke in C# and don’t get compilation errors and it works well at runtime on a 64-bit system, but I’m not sure how importing native libraries differs between C# and C++.

In C# you write the call signature manually, for example:

and I don’t think the linker is involved. C# is generally JIT compiled so the compiler only compiles it to architecture-independent bytecode, then at runtime it compiles to machine code and optimizes it for the architecture + processor it’s running on. C# apps are generally compiled as “Any CPU” which means the same EXE works on both 32-bit and 64-bit machines (thanks to JIT compiling). C# does support AoT (Ahead of Time) compilation now, but I’ve not tested the gpgme-sharp library with it.

As for finding the DLL… In my C# code, I have a list of paths that it looks for - first checking the registry then falling back to a hard-coded %ProgramFiles(x86)%\Gpg4Win:

This is used with a custom DLL resolver (.NET feature NativeLibrary.SetDllImportResolver) that loads the correct DLL based on if the process is 32-bit or 64-bit. Essentially it’s like using Win32 LoadLibrary and GetProcAddress.

Thank you, I now realize that linking in C# and C++ is very different and that you had to use extern with all the C functions. Unfortunately, even if I could Win32 LoadLibrary in C++ Windows, which might fix the compatibility issue, it would be too hard for me to manage the memory correctly on the caller side in C, and that is beyond my abilities.

I saw your successful attempt to load the pgpme dll in C# at runtime, and I wanted to try it myself using boost:dll. However, it did not work for me. I could load other system dlls, but the gpgme dll failed with an incompatibility error.

#include <boost/dll/import.hpp>         // for dll::import
#include <boost/dll/shared_library.hpp> // for dll::shared_library
#include <boost/function.hpp>
#include <iostream>
#include <windows.h>
#include <gpgme.h>

namespace dll = boost::dll;

int main() {
    typedef HANDLE(__stdcall GetStdHandle_t)(DWORD );
    dll::shared_library lib2("C:/Windows/System32/KERNEL32.DLL", dll::load_mode::search_system_folders);
    GetStdHandle_t& func = lib2.get<GetStdHandle_t>("GetStdHandle");
    std::cout << "1.0 GetStdHandle() returned " << func(STD_OUTPUT_HANDLE) << std::endl<<lib2.location();

    //CRASH HERE
    dll::shared_library lib("C:/Program Files (x86)/Gpg4win/bin_64/libgpgme6-11.dll", dll::load_mode::search_system_folders);

    return 0;
}