I have created this dll in Go with an exported function which works fine while I'm calling it with rundll32 or from a c++ executable with the loadlbraryA. But I get an error when calling from c++ dll which I tried to read GetLastError()
And it says cannot find the module you are calling
. I tried every possible way to give the full path to loadlibraryA but the same error happens and the handle to Go DLL is null every time. Also, I examined the Go DLL, and the Test function is exported properly.
In short, It works in calling Test():
- From rundll32
- From c++ main() and loadlibrary
And doesn't work in Test():
- From c++ DllMain() and loadlibrary
- From c++ DllMain() and loadlibrary directly called from kernel32.dll
- From c++ DllMain() and a ThreadFunction created in DllMain()
Folder structure
ProjectFolder
-- main.go
-- dllmain.h
-- dllmain.go
Build with
go build -buildmode=c-shared -o my-go-library.dll main.go
Call example dll
rundll32 my-go-library.dll Test
Working source
main.go:
package main
import "C"
import (
"syscall"
"time"
"unsafe"
)
//export Test
func Test() {
MessageBoxPlain("TestMsgbox","Test")
main()
}
//export OnProcessAttach
func OnProcessAttach() {
MessageBoxPlain("OnAttachMsgbox","OnAttach")
Test()
}
// MessageBox of Win32 API.
func MessageBox(hwnd uintptr, caption, title string, flags uint) int {
ret, _, _ := syscall.NewLazyDLL("user32.dll").NewProc("MessageBoxW").Call(
uintptr(hwnd),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(title))),
uintptr(flags))
return int(ret)
}
// MessageBoxPlain of Win32 API.
func MessageBoxPlain(title, caption string) int {
const (
NULL = 0
MB_OK = 0
)
return MessageBox(NULL, caption, title, MB_OK)
}
func main() {}
dllmain.h:
#include <windows.h>
void OnProcessAttach(HINSTANCE, DWORD, LPVOID);
typedef struct {
HINSTANCE hinstDLL; // handle to DLL module
DWORD fdwReason; // reason for calling function // reserved
LPVOID lpReserved; // reserved
} MyThreadParams;
DWORD WINAPI MyThreadFunction(LPVOID lpParam) {
MyThreadParams params = *((MyThreadParams*)lpParam);
OnProcessAttach(params.hinstDLL, params.fdwReason, params.lpReserved);
free(lpParam);
return 0;
}
BOOL WINAPI DllMain(
HINSTANCE _hinstDLL, // handle to DLL module
DWORD _fdwReason, // reason for calling function
LPVOID _lpReserved) // reserved
{
switch (_fdwReason) {
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
{
MyThreadParams* lpThrdParam = (MyThreadParams*)malloc(sizeof(MyThreadParams));
lpThrdParam->hinstDLL = _hinstDLL;
lpThrdParam->fdwReason = _fdwReason;
lpThrdParam->lpReserved = _lpReserved;
HANDLE hThread = CreateThread(NULL, 0, MyThreadFunction, lpThrdParam, 0, NULL);
// CreateThread() because otherwise DllMain() is highly likely to deadlock.
}
break;
case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
}
return TRUE; // Successful.
}
dllmain.go:
package main
//#include "dllmain.h"
import "C"
C++ DLL
Now the c++ dll source which calls Test
from my-go-library.dll
:
#include "pch.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <winternl.h>
#include <malloc.h>
#include <intrin.h>
#include <Windows.h>
#include <winternl.h>
#include <malloc.h>
#include <ostream>
#include <iostream>
#include <string>
using namespace std;
typedef int(__stdcall* TestFromGo)();
void Error()
{
wchar_t err[256];
memset(err, 0, 256);
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err, 255, NULL);
int msgboxID = MessageBoxW(NULL,err,(LPCWSTR)L"Error",MB_OK);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
MessageBoxA(0, "The C++ DLL", "title", 0);
HINSTANCE hGetProcIDDLL = LoadLibraryA("C:\\User\\.....path to go dll.....\\my-go-library.dll");
if (!hGetProcIDDLL) {
Error();
MessageBoxA(0, "could not load the dynamic library", "Test", 0);
}
TestFromGo TestFunction = (TestFromGo)GetProcAddress(hGetProcIDDLL, "Test");
if (!TestFunction) {
MessageBoxA(0, "could not locate the function", "Test", 0);
}
TestFromGo();
}
extern "C" __declspec(dllexport) void jojo()
{
DllMain(0, 1, 0);
}
Calling the c++ dll
Now this one supposed to call jojo
then DllMain
then calling my-go-library.dll
and Test
rundll32 theCiplasplas.dll jojo
LoadLibrary
fromDllMain
. – dxiv