Я только что протестировал игрушечный проект надстройки Excel, кросс-сборку XLL с цепочками инструментов mingw32.
Вот мой код:
//testXLL.c
#include "windows.h"
#include "xlcall.h"
#define MEMORYSIZE 65535000
char vMemBlock[MEMORYSIZE];
int vOffsetMemBlock =0;
LPSTR GetTempMemory(int cBytes){
LPSTR lpMemory;
if(vOffsetMemBlock + cBytes > MEMORYSIZE)
return 0;
else{
lpMemory = (LPSTR) &vMemBlock + vOffsetMemBlock;
vOffsetMemBlock += cBytes;
if(vOffsetMemBlock & 1) vOffsetMemBlock++;
return lpMemory;
}
}
LPXLOPER TempStr(LPSTR lpstr){
LPXLOPER lpx;
int chars;
lpx = (LPXLOPER)GetTempMemory(sizeof(XLOPER));
if(!lpx) return 0;
chars = lstrlen(lpstr);
if(chars>255) chars=255;
lpx->val.str=(char*)GetTempMemory((sizeof(char)*chars+1));
if(!lpx->val.str) return 0;
strncpy(lpx->val.str, lpstr,chars);
lpx->val.str[0]=(BYTE) chars;
//lpx->val.str[chars]='\0';
lpx->xltype = xltypeStr;
return lpx;
}
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) double __stdcall myadd2(double a1,double a2){
return a1+a2;
}
static char functionTable[11][255] =
{" myadd2", // procedure
" BBB", // type_text
" add", // function_text
" add1,add2", // argument_text
" 1", // macro_type
" category", // category
" ", // shortcut_text
" some help topic", // help_topic
" Adds toy", // function_help
" 1st.", // argument_help1
" 2nd" // argument_help2
};
__declspec(dllexport) int __stdcall xlAutoOpen(){
LPXLOPER pxDLL;
Excel4(xlGetName,pxDLL,0);
XLOPER xlRegArgs[11];
for(int i = 0; i < 11; i++){
xlRegArgs[i] = *TempStr(functionTable[i]);
}
Excel4(xlfRegister, 0, 12,
pxDLL,
&xlRegArgs[0], &xlRegArgs[1], &xlRegArgs[2],
&xlRegArgs[3], &xlRegArgs[4], &xlRegArgs[5],
&xlRegArgs[6], &xlRegArgs[7], &xlRegArgs[8],
&xlRegArgs[9], &xlRegArgs[10]);
return 1;
}
__declspec(dllexport) LPXLOPER __stdcall xlAddInManagerInfo(LPXLOPER xlAction) {
static XLOPER xlReturn, xlLongName, xlTemp;
xlTemp.xltype = xltypeInt;
xlTemp.val.w = xltypeInt;
Excel4(xlCoerce, &xlReturn, 2, xlAction, &xlTemp);
if(1 == xlReturn.val.w) {
xlLongName = *TempStr(" xll-name");
} else {
xlLongName.xltype = xltypeErr;
xlLongName.val.err = xlerrValue;
}
return &xlLongName;
}
#ifdef __cplusplus
}
#endif
Я создал этот файл testXLL.c в Ubuntu:
>i686-w64-mingw32-gcc -shared -Wl,--kill-at testXLL.c -o win.xll -L. -lxlcall32
Это успешно создает файл win.xll, но при загрузке этого файла win.xll происходит сбой Excel.
В Windows 10 я пытался использовать gdb для его отладки, но я не могу поймать точку останова в файле xll — он отключается автоматически при загрузке. Но я вижу в выводе gdb, что это ошибка сегментации при сбое Excel.
XLOPER xlRegArgs[11];
for(int i = 0; i < 11; i++){
xlRegArgs[i] = *TempStr(functionTable[i]);
}
Странно то, что если я заменю приведенный выше цикл for
следующими построчными назначениями в функции xlAutoOpen
, скомпилированный файл XLL отлично работает в Excel:
XLOPER xlRegArgs[11];
xlRegArgs[0] = *TempStr(functionTable[0]);
xlRegArgs[1] = *TempStr(functionTable[1]);
xlRegArgs[2] = *TempStr(functionTable[2]);
xlRegArgs[3] = *TempStr(functionTable[3]);
xlRegArgs[4] = *TempStr(functionTable[4]);
xlRegArgs[5] = *TempStr(functionTable[5]);
xlRegArgs[6] = *TempStr(functionTable[6]);
xlRegArgs[7] = *TempStr(functionTable[7]);
xlRegArgs[8] = *TempStr(functionTable[8]);
xlRegArgs[9] = *TempStr(functionTable[9]);
xlRegArgs[10] = *TempStr(functionTable[10]);
Пожалуйста, просветите меня. В чем разница между этими двумя подходами к назначению?
if(chars>255) chars=255;
должен быть 254, чтобы включать завершающий нуль. Послеstrncpy
вы должны завершить строку по индексу 254. - person Paul Ogilvie   schedule 01.04.2021Excel4(xlfRegister, 0, 12,
может потребоваться 11. - person Paul Ogilvie   schedule 01.04.2021i
) переменнойstatic
вне функции; если это работает, то это похоже на какую-то проблему с повреждением стека. Я копну немного глубже, чтобы увидеть, решил ли я когда-либо проблему. - person Adrian Mole   schedule 01.04.2021__debugbreak();
перед циклом, указал Excel в качестве хоста для отладки DLL и начал отладку. Когда отладчик достигает точки останова, установите ловушку данных наi
и несколько раз осторожно перешагните через (F10), соблюдая значениеi
. Этот https://stackoverflow.com/a/49079078/8666197 может помочь вам добавить жесткую точку останова в gcc. В качестве альтернативы используйте отладку для бедняков с помощьюMessageBox
илиOutputDebugString
, если gdb поддерживает это. - person Daniel Sęk   schedule 07.04.2021