0

So I want to use the redemption COM library in go.
I could already successfully use it by registering it first and then using Go-OLE to call functions.

But ideally I want to use it without having to register it first.
When I searched on linking a dll in go I have found many answers saying to use cgo, but I could not find a tutorial, describing on how to use cgo.

After reading the cgo documentation, and this answer about cross compiling (I am cross compiling from Ubuntu linux amd64 to windows amd64) I figured that I could probably use the dll by setting my environment variables to

GOOS=windows;GOARCH=amd64;CGO_ENABLED=1;CXX=x86_64-w64-mingw32-g++;CC=x86_64-w64-mingw32-gcc

And writing a go file like this

package main

//#cgo windows LDFLAGS: -L/go/src/tryingout/Redemption64.dll
import "C"
import "fmt"

func main() {
    session := C.Redemption.RDOSession
    fmt.Println(session)
}

Unfortunately this did not work, I received the could not determine kind of name for C.Redemption error at compilation. I have looked it up and it means that Redemption does not exist. But I do know that it should be called like this since 1)It should be according to the documentation of redemption and 2) It worked before with go-ole

There is also a loader class written in C#, C++ and other languages by the redemption developer but I could not use that either because it was somehow always interpreted as C instead of C++ and thus resulted in errors. I tried this solution and added -lstdc++ to my LDFLAGS, but it made no difference.

So my question is how do I load and use this COM library or where can I find a tutorial/example code that explains it?

  • From a cursory look, my impression is what's missing is an inclusion of a header file actually _defining_ (for `cgo` and `gcc` it will call) the types and functions in the DLL. I mean, "old" DLLs (not those files produced by .NET compilers which bear almost no resemblance to those "old" libraries except the extension part of their filenames) do not contain any information in them directly digestible by `cgo`. The latter has no direct support for COM and won't extract TLB info from the DLL (even if present). – kostix Dec 10 '18 at 15:49
  • So the question is: does that "redemption" thing provide one or more "public" `.h` files suitable for feeding to a C compiler? Also note that while `cgo` is able to build C++ sources, it's not able to parse C++ from header files—hence it only is able to _compile_ C++ code, but if you want to use it via `cgo`, the library must export a set of symbols using the C++'s `extern "C" { ... }` declaration. – kostix Dec 10 '18 at 15:51
  • Thank you for this information, I did not know `cgo` needs a `.h` file to digest a DLL library. To your question: As far as I know, the only `.h` file that I can access is the `RedemptionLoader.h` file which comes together with the `RedemptionLoader.cpp` file. And if I see this correctly the `RedemptionLoader.h` file is written in C++. – frieder Dec 10 '18 at 22:15
  • The `RedemptionLoader.cpp` does not export symbols, so I will look into if I can export the necessary symbols myself using the documentation that I have. Tank you again for your helpful comments. – frieder Dec 10 '18 at 22:28
  • It looks like you for some reason do not want to call directly into that DLL using the `syscall` package (while I'd say on Windows it's vastly better an approach than using `cgo`). If so, and the library is pure C++ w/o a C-compatible exported API, you maybe should turn to [SWIG](http://www.swig.org/Doc3.0/Go.html) which is a sort-of officially blessed way to interface C++ with Go. – kostix Dec 11 '18 at 10:06
  • Please note that should you succeed with either approach, do not forget that you _have to_ call `CoInitialize[Ex]` in the thread in which you intend to instantiate and use any COM\[+\] objects. `go-ole` has it already available. Also note that since the Go runtime implements the so-called M×N scheduling, any goroutine is free to run on any OS thread available to the scheduler at any given time. IOW it may switch threads at any time, and `CoInitialize[Ex]` initializes a thread, not a goroutine. – kostix Dec 11 '18 at 10:09
  • This, in turn, means that the most robust approach would be to first have a dedicated goroutine to work with those COM objects, and have it call `runtime.LockOSThread()` _before_ is initializes its thread for being able to work with COM. That call makes sure the underlying thread will forever be assigned to that goroutine—until it exits or calls `runtime.UnlockOSThread`. – kostix Dec 11 '18 at 10:11
  • Regarding «Thank you for this information, I did not know cgo needs a .h file to digest a DLL library»—if you'll dump a DLL using any suitable tool (such as `objdump`) you'll notice that all it basically has "exported" is two lists of _names_ of the functions: the one it provides and the one it needs to be linked in after loading. There is no information on types using to compile the library. That is basically an artefact of the distant past where "a library" meant a library of subroutines. See [this](https://en.wikipedia.org/wiki/Name_mangling) for more info. – kostix Dec 11 '18 at 10:15
  • I had the misconception, that directly calling into the DLL using the `syscall` package would only work for already registered DLLs, after trying code adapted from [here](https://tips.efmsoft.com/creating-a-com-object-wo-registration/) and [here](https://stackoverflow.com/a/46234640/10107341) I now see that I must have made a mistake earlier that lead me to the false conclusion. Unfortunately I don't know if the library is pure C++, since I only have the compiled DLL files, but if I encounter problems, directly calling into the DLL, I will definitively have a look at SWIG. – frieder Dec 17 '18 at 12:48
  • I was aware of the necessity of `CoInitialize[Ex]`, but I did not think about the instability that comes with thread switching. Your note is very good advice and I will apply it to all of my go programs that use COM objects. – frieder Dec 17 '18 at 13:06

0 Answers0