Search code examples
jnacgo

JNA to Go DLL - How do I get String returned from Go Func?


I have a Java program that is using JNA to call a Go Func. Here's the Interface to the Go func in Java:

public interface GPG extends Library {
    // GoString class maps to: C type struct { const char *p; GoInt n; }
    public class GoString extends Structure {
        public static class ByValue extends GoString implements Structure.ByValue {}
        public String p;
        public long n;
        protected List getFieldOrder(){
            return Arrays.asList(new String[]{"p","n"});
        }
    }
    // Foreign functions
    public GoString.ByValue decrypt(GoString.ByValue encString, GoString.ByValue secretKeyring, GoString.ByValue passphrase);
}

The func signature in Go is:

func decrypt(encString string, secretKeyring string, passphrase string) string

The Go generated C header has:

/* Created by "go tool cgo" - DO NOT EDIT. */

/* package command-line-arguments */


#line 1 "cgo-builtin-prolog"

#include <stddef.h> /* for ptrdiff_t below */

#ifndef GO_CGO_EXPORT_PROLOGUE_H
#define GO_CGO_EXPORT_PROLOGUE_H

typedef struct { const char *p; ptrdiff_t n; } _GoString_;

#endif

/* Start of preamble from import "C" comments.  */




/* End of preamble from import "C" comments.  */


/* Start of boilerplate cgo prologue.  */
#line 1 "cgo-gcc-export-header-prolog"

#ifndef GO_CGO_PROLOGUE_H
#define GO_CGO_PROLOGUE_H

typedef signed char GoInt8;
typedef unsigned char GoUint8;
typedef short GoInt16;
typedef unsigned short GoUint16;
typedef int GoInt32;
typedef unsigned int GoUint32;
typedef long long GoInt64;
typedef unsigned long long GoUint64;
typedef GoInt64 GoInt;
typedef GoUint64 GoUint;
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
typedef float _Complex GoComplex64;
typedef double _Complex GoComplex128;

/*
  static assertion to make sure the file is being used on architecture
  at least with matching size of GoInt.
*/
typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];

typedef _GoString_ GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;

#endif

/* End of boilerplate cgo prologue.  */

#ifdef __cplusplus
extern "C" {
#endif


extern GoString decrypt(GoString p0, GoString p1, GoString p2);

#ifdef __cplusplus
}
#endif

I call the Go Func from Java using this code:

                GPG gpg = (GPG) Native.loadLibrary("C:/lib/gpg.dll", GPG.class);
                GPG.GoString.ByValue encString = new GPG.GoString.ByValue();
                encString.p = value;
                encString.n = encString.p.length();
                GPG.GoString.ByValue secretKeyring = new GPG.GoString.ByValue();
                secretKeyring.p = "c:/gnupg/secring.gpg";
                secretKeyring.n = secretKeyring.p.length();
                GPG.GoString.ByValue passphrase = new GPG.GoString.ByValue();
                passphrase.p = "SecretPassPhrase";
                passphrase.n = passphrase.p.length();
                GPG.GoString.ByValue decValue = gpg.decrypt(encString, secretKeyring, passphrase);

Clearly the func is being called and processes up to the return of the result string. But it then produces: "panic: runtime error: cgo result has Go pointer" How do I get a String result back from Go? Using go version go1.10 windows/amd64, JNA 4.5.1, Java 1.8.0_152


Solution

  • Your GO function should looks like this:

    //export decrypt
    func decrypt(encString string, secretKeyring string, passphrase string) *C.char {
        //... your code here
        var str string = "returning string"
        return C.CString(str)
    }
    

    Java Interface:

    public String decrypt(GoString.ByValue encString, GoString.ByValue secretKeyring, GoString.ByValue passphrase);