使用MinGW gcc为VBA 64位创建DLLs。

问题描述 投票:0回答:1

我想按标题所说的做。这个问题之前已经讨论过了(如何使用gcc编译器Mingw创建dll,用于visual basic?),但这些帖子都是10年前的了。当时我写ExcelVBA宏没有困难,但现在我想更新到64位Windows。从那时起我也换了编译器。我在创建DLL时没有遇到任何问题,用 gccgfortrangccPython. 兼容性问题很难理解,因为你不知道一篇文章是什么时候写的,也不知道它在64位世界是否还有效。你可能会叮嘱我重提这个老话题,但也许其他人也有类似的问题。我也发现了一篇优秀的文章(https:/www.transmissionzero.co.ukcomputingbuilding-dlls-with-mingw). 我已经尝试着按照这两个方法去做,但在Excel电子表格中却什么都做不了。也许我犯了一个对别人来说很明显的错误。下面是函数。code.c:

__declspec(dllexport) int __stdcall sqint(int x){
   return x * x;
}

我用DLL构建。

gcc code.c -shared -o code.dll -s -Wl,--subsystem,windows,--kill-at,-Map=code.map

code.map文件和objdump实用程序都显示了该函数,例如,这里有几行来自于 objdump -p code.dll:

[Ordinal/Name Pointer] Table
    [   0] sqfloat
    [   1] sqint

其中 sqfloat 是一个类似的带有双倍的代码。地图文件还显示了对库的引用,比如。

/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../lib/libcygwin.a

接下来,我在VBA中声明:

Declare PtrSafe Function sqint Lib "C:\Cwin\mix\code.dll" (ByVal x As Long) As Long

visual basic long和gcc int都应该是4个字节。我应该可以直接调用这个函数,但是在调试的时候我试着把它放在另一个函数里面。用VBA调试器,我可以看到传递给函数的值,但我除了得到可怕的 #VALUE!. 如果你看到我做错了什么,我会感谢你的意见。

更新722020:我对这个问题又进行了一次尝试,但成功率有限。我相信我创建的DLL不是64位的。我想这应该是默认的。现在的构建是这样的。

gcc code.c -Wa,-march=generic64 -shared -o code.dll -s -Wl,--subsystem,windows,--kill-at,-Map=code.map

按照这个帖子 如何测试DLL,使用 file code.dll 给。

code.dll: PE32+ executable (DLL) (GUI) x86-64 (stripped to external PDB), for MS Windows

sqfloat函数现在返回了一个正确的结果 但最终Excel还是失败了,关闭了。sqint函数返回2*2=1。我尝试使用 Integer 而不是 long但没有变化。难道MSVBA改变了long的定义?

所以目前的状况是我偶尔会得到一个结果,但宏会杀死Excel。

vba gcc dll 64-bit mingw
1个回答
1
投票

我正试图创建一个C封装的DLL来连接一个用CDECL调用约定编写的商业DLL,这样它就可以和现有的用Excel VBA编写的程序接口(因此使用STDCALL调用约定)。

我有完全相同的问题,可能是在尝试了非常类似的事情之后。我试过使用mingw (gcc & g++, 32 & 64 bits)和cygwin gcc flavors (gcc & g++ 32 & 64 bits)。运气不好,我怀疑是编译器的问题。

我怀疑是编译器或链接器的问题,因为一些编译器组合产生的DLL不被VBA识别(尽管它们可以被stub exe调用),并抛出一个错误53-DLL not found。其他组合则给出了另一个错误(48-错误加载DLL),当然代码也是一样的。

我使用的是Windows 10 64位和Office 64位。

这是 wrapper.c:

    #include "wrapper.h"
    #include <windows.h>
    #include <stdio.h>

    #ifdef cplusplus
    extern "C"
    {
    #endif

    PCNC_EXPORT void __stdcall WrFreeString(char* str)
    {
        //Memory
        return FreeString(str);
    }
    PCNC_EXPORT int __stdcall WrGetVer()
    {
        return GetVer();
    }
    PCNC_EXPORT char* __stdcall WrGetLibPath()
    {
        return GetLibPath();
    }

    // snip ___


    PCNC_EXPORT BOOL __stdcall DllMain(HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }

    #ifdef cplusplus
    }
    #endif

wrapper.h:

    #include "PlanetCNCLib.h"
    #include "PlanetCNCLibTypeDef.h"

    #ifdef cplusplus
    extern "C"
    {
    #endif

    PCNC_EXPORT void __stdcall WrFreeString(char* str);
    PCNC_EXPORT int __stdcall WrGetVer();
    PCNC_EXPORT char* __stdcall WrGetLibPath();

    #ifdef cplusplus
    }
    #endif

来自PlanetCNCLib.h:

    #ifndef __PlanetCNCLib_H__
    #define __PlanetCNCLib_H__


    #include "PlanetCNCLibTypeDef.h"


    #ifdef __cplusplus
    extern "C" {
    #endif


    #ifndef PCNC_EXPORT
    #   ifdef _WIN32
    #       define PCNC_EXPORT __declspec(dllexport)
    #   else
    #       define PCNC_EXPORT __attribute__((visibility("default"))) 
    #   endif
    #endif

    // etc

还有Makefile:

    #CPP=/usr/bin/i686-w64-mingw32-g++.exe   # doesnt work (err 48 err loading DLL)
    #CPP=/usr/bin/x86_64-w64-mingw32-g++.exe # doesnt work (err 53 DLL not found)
    #CPP=/usr/bin/i686-pc-cygwin-g++         # doesnt work (err 48 err loading DLL) 
    #CPP=/usr/bin/x86_64-pc-cygwin-g++.exe   # doesnt work (err 53 DLL not found)
    #CPP=gcc                                 # doesnt even compile

    #LD=/usr/bin/i686-w64-mingw32-ld.exe
    #LD=/usr/bin/x86_64-w64-mingw32-ld.exe
    LD=$(CPP)

    LDFLAGS=-shared -L/usr/lib -L./lib/ -Wl,--add-stdcall-alias #--kill-at
    CFLAGS=-c

    all: PlanetCNCWrapper.dll

    wrapper.o:PlanetCNCLib.h PlanetCNCLibTypeDef.h wrapper.c
        $(CPP) -o $@ wrapper.c  $(CFLAGS)

    PlanetCNCWrapper.dll:wrapper.o
        $(LD) $(LDFLAGS) -o $@ $? -L./lib/ lib/PlanetCNCLib64.lib -lPlanetCNCLib64 

    clean:
        rm -f *.o *.e *~ .*~ *stackdump PlanetCNCWrapper.dll

其他有用的数据。

    Windows Version 1909 (OS Build 18363.778)
    System type: 64-bit operating system, x64-based processor
    Microsoft Excel for Office 365 MSO (16.0.11929.20708) 64 bits
    i686-w64-mingw32-g++ (GCC) 9.2.0
    x86_64-w64-mingw32-g++ (GCC) 9.2.0
    i686-pc-cygwin-g++ (GCC) 6.4.0
    x86_64-pc-cygwin-g++ (GCC) 9.3.0

忘记补充了 --add-stdlib-alias似乎没有任何作用: 无论是否有这个标志, 符号都会被装饰在DLL中.

© www.soinside.com 2019 - 2024. All rights reserved.