我想按标题所说的做。这个问题之前已经讨论过了(如何使用gcc编译器Mingw创建dll,用于visual basic?),但这些帖子都是10年前的了。当时我写ExcelVBA宏没有困难,但现在我想更新到64位Windows。从那时起我也换了编译器。我在创建DLL时没有遇到任何问题,用 gcc
或 gfortran
被 gcc
或 Python
. 兼容性问题很难理解,因为你不知道一篇文章是什么时候写的,也不知道它在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。
我正试图创建一个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中.