@squadglad, it is certainly possible to compile go code into a windows DLL, 
and to use cgo. I've done it successfully.
You'll want to study up on cgo. There are strict rules for keeping go 
pointers and C pointers apart, and they
can be subtle. You'll need to be become well versed in the details 
discussed here https://pkg.go.dev/cmd/cgo .
Also you are back in the land of malloc() and free(), where it is easy to 
footgun yourself with a memory leak.

So its not the easiest design to make work. I would recommend generally 
against it, 
if you can avoid it. 

Each Go DLL (if there are multiple) will have its own copy of the Go 
runtime, which sets various signal handlers. The host
process, if Go based, will also have a runtime, and it will set various 
signal handlers.
Now we're getting into really dicey territory, which I happen to be working 
with just now,
since signal handling is going to be different on unix and windows, and 
you'll have to carefully figure out how to 
coordinate; this might not even be possible if you don't control the host 
process.
To say, "there be dragons" on the map, is apt.

I'll go into one particularly other subtle point to illustrate the hazards 
on Windows of Go DLLs:

The biggest gotcha that isn't well known is that your go DLL on windows 
will not behave like a normal windows DLL. Once it
is loaded, it cannot be unloaded. The go runtime starts background 
goroutines (threads), and there
is no way to safely stop these. Hence if you unload a c-shared Go DLL from 
a windows process,
it will crash the process when those threads try to run their code at 
addresses that no longer have
code after the DLL unload.

There is a partial workaround. Windows lets you pin a DLL to a process. 
Then, even if the
host process tries to unload the DLL, that request will be ignored.  If you 
control
the host process code, then you should simply never call FreeLibrary(). I 
was in
a situation some time back where I did not control the host process, and it 
would
try to unload my Go based DLL, and thus crash.  I had to pin the DLL to the 
process, so that
the FreeLibrary() call on it becomes a no-op. Something like this:

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved) {

  switch(ul_reason_for_call) {
    case DLL_PROCESS_ATTACH:
      LockLibraryIntoProcessMem(hModule, &g_Self);

      // On XP or later you can use GetModuleHandleEx with the 
      // GET_MODULE_HANDLE_EX_FLAG_PIN flag to prevent unloading of the 
DLL. 
      // Really strong. Can't be undone by double FreeLibrary().
      GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, &g_ModuleName[0], 
&g_Self2);

      break;
    case DLL_PROCESS_DETACH:
      break;
    }
  return TRUE;
}

// Lock this DLL in memory (since we'll crash if it gets unloaded due to
// running background threads suddenly finding their code pages gone).
// 
https://blogs.msmvps.com/vandooren/2006/10/09/preventing-a-dll-from-being-unloaded-by-the-app-that-uses-it/
HMODULE g_Self;
HMODULE g_Self2;
HHOOK   g_Hook;
TCHAR   g_ModuleName[1024];

// sets *LocalDllHandle == g_Self, and g_ModuleName, as side effects.
int LockLibraryIntoProcessMem(
                              HMODULE DllHandle,
                              HMODULE *LocalDllHandle)
{
  if(NULL == LocalDllHandle) {
    return ERROR_INVALID_PARAMETER;
  }
  *LocalDllHandle = NULL;
  if(0 == GetModuleFileName(
                            DllHandle,
                            g_ModuleName,
                            sizeof(g_ModuleName)/ sizeof(TCHAR)))
    return GetLastError();
  *LocalDllHandle = LoadLibrary(g_ModuleName);
  if(NULL == *LocalDllHandle)
    return GetLastError();
  return NO_ERROR;
}

Usually you would unload and re-load a DLL only to upgrade its code 
while keeping the host process running. That isn't going to be possible
when the DLL is pinned.  You have to restart the host process to
change the go code.  At this point, if you control the host code,
you might well conclude that it is easier to just compile the go
code into the host process, and skip the whole DLL thing. 

And you would be right.




On Monday, October 3, 2022 at 11:47:49 PM UTC-5 squadglad. wrote:

> We have some disk space restrictions and hence we do not want to include 
> the common code as a library in the service. That will increase the size of 
> each exe. We would like to keep the common code and service code 
> independent of each other. Changes in one should not affect or cause 
> recompilation of the other.
>
> On Mon, Oct 3, 2022 at 4:01 PM Brian Candler  wrote:
>
>> On Monday, 3 October 2022 at 10:40:06 UTC+1 squadglad wrote:
>>
>>> We are trying to use a common code as a DLL which is shared by multiple 
>>> services.
>>>
>>
>> You've mixed a problem and solution statement together.
>>
>> You want to share code between multiple services: if so, there are other 
>> solutions to this problem.  For example, you could provide it as a library 
>> which is compiled into those services (that's by far the simplest option).  
>> Or you could put it in some other process that you call using gRPC.  Or you 
>> could spawn another process and talk to it over stdin/stdout using a 
>> protocol of your choice.
>>
>> What's unclear to me is why you want the *dynamic linking* part of this. 
>> Is there some requirement which means you need to be able to swap out this 
>> shared code *at runtime*, without recompiling the underlying service which 
>> uses that code?
>>
>> -- 
>>
> You received this message because you are subscribed to a topic in the 
>> Google Groups "golang-nuts" group.
>> To unsubscribe from this topic, visit 
>> https://groups.google.com/d/topic/golang-nuts/pk6vPUmx6lY/unsubscribe.
>> To unsubscribe from this group and all its topics, send an email to 
>> golang-nuts...@googlegroups.com.
>>
> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/golang-nuts/1600edf5-9969-400c-a358-e4e0c3e4ca8en%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/golang-nuts/1600edf5-9969-400c-a358-e4e0c3e4ca8en%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/1a228de3-3546-45af-94e1-d76cf6964165n%40googlegroups.com.

Reply via email to