Excel 2003、Windows XP SP3:
非常に大規模で複雑なExcelブックを操作するExcelユーザーが多数います。一般的なワークブックには60以上のワークシートがあり、サイズは70MB以上です。作成した.xllアドインがあり、これらのスプレッドシート全体で使用されています。アドインには、広範なデバッグ機能とログ機能があります。アドインのバージョンを作成し、ほぼ10年間使用しています。したがって、Excelインターフェイスのインフラストラクチャは、堅牢で安定していることが証明されています。
Excelが特定のコードでハングする特定の状況があります。つまり、Excel自体のコード内にハングし、特定の1つのコードにハングします。この場合、コードのタイトなループ(おそらく、「呼び出し」のない20のマシン命令)があり、それが際限なく実行されます。コードは循環するリンクリストを歩いているように見えます。多くの場合、ノードは少なく、たとえば4つのノードしかありません。評価ツリー(の一部)に対応するリンクリストを歩いているように見えますが、まったくわかりません。
信じられないほど単純なアドイン(固定データを返す3つの登録済み関数)と信じられないほど単純なスプレッドシート(5つのセル、3つのアドイン関数を使用する3つの数式)で動作を明示することができました。ワークシートのすべてのセルの評価が完了し、結果で画面を更新した後にのみ、Excelがハングします。使用されているExcelSDKのバージョンに関係なくハングします(v5.0、v12.0、およびv14.0はすべてテスト済み)。
サンプルコードへのリンクは次のとおりです。サンプルの.xlsワークブックと対応する.xllアドインおよびアドインのソース
アドインのソースは簡単です。
#include <windows.h>
#if SDK_VER == 5
#include "xlcall_v5_0.h"
#elif SDK_VER == 12
#include "xlcall_v12_0.h"
#elif SDK_VER == 14
#include "xlcall_v14_0.h"
#endif
extern "C" __declspec(dllexport) int xlAutoOpen(void) {
#define N_FUNCTIONS 3
#define N_FUNCTION_REGISTRATION_PARAMETERS 3
char* rgFuncs[N_FUNCTIONS][N_FUNCTION_REGISTRATION_PARAMETERS] = {
{"\013FunctionOne", "\002RP", "\013FunctionOne"},
{"\013FunctionTwo", "\002RP", "\013FunctionTwo"},
{"\014FunctionFour", "\003RBP", "\014FunctionFour"} };
XLOPER xlFuncParams[N_FUNCTION_REGISTRATION_PARAMETERS+1];
LPXLOPER ppxlFuncParams[N_FUNCTION_REGISTRATION_PARAMETERS+1];
Excel4(xlGetName, (ppxlFuncParams[0] = &xlFuncParams[0]), 0);
for(int i = 0; i < N_FUNCTIONS; i++) {
for (int j = 1; j <= N_FUNCTION_REGISTRATION_PARAMETERS; j++) {
xlFuncParams[j].xltype = xltypeStr;
xlFuncParams[j].val.str = rgFuncs[i][j-1];
ppxlFuncParams[j] = &xlFuncParams[j];
}
Excel4v(xlfRegister, 0, N_FUNCTION_REGISTRATION_PARAMETERS+1, ppxlFuncParams);
}
Excel4(xlFree, 0, 1, (LPXLOPER)&xlFuncParams[0]);
return 1;
}
extern "C" __declspec(dllexport) LPXLOPER xlAddInManagerInfo(LPXLOPER xAction) {
static XLOPER xInfo;
XLOPER xloCoerceType, xIntAction;
xloCoerceType.xltype = xltypeInt; xloCoerceType.val.w = xltypeInt;
Excel4(xlCoerce, &xIntAction, 2, xAction, (LPXLOPER)&xloCoerceType);
if( xIntAction.xltype == xltypeInt && xIntAction.val.w == 1) {
xInfo.xltype = xltypeStr;
xInfo.val.str = "\010ExcelBug";
} else {
xInfo.xltype = xltypeErr;
xInfo.val.err = xlerrValue;
}
return (LPXLOPER)&xInfo;
}
LPXLOPER XLReturn(const double* pdData, const int nData, bool bRow=false) {
static XLOPER xlDLLResult;
static int nAllocated = 0;
if( nAllocated==0 ) {
xlDLLResult.xltype = xltypeMulti;
nAllocated=max(nData,2);
xlDLLResult.val.array.lparray = new XLOPER[nAllocated];
} else if( nAllocated < nData ) {
delete [] xlDLLResult.val.array.lparray;
nAllocated = nData;
xlDLLResult.val.array.lparray = new XLOPER[nAllocated];
}
for(int i = 0; i < nData; ++i) {
xlDLLResult.val.array.lparray[i].xltype = xltypeNum;
xlDLLResult.val.array.lparray[i].val.num = pdData[i];
}
xlDLLResult.val.array.rows = (WORD)(bRow? 1 : nData );
xlDLLResult.val.array.columns = (WORD)(bRow? nData : 1 );
return (LPXLOPER) &xlDLLResult;
}
extern "C" __declspec(dllexport) LPXLOPER FunctionOne( LPXLOPER ) {
double dData = 41144.;
return XLReturn(&dData, 1);
}
extern "C" __declspec(dllexport) LPXLOPER FunctionTwo( LPXLOPER ) {
const double pdData[2] = {41145., 41176.};
return XLReturn(pdData, 2);
}
extern "C" __declspec(dllexport) LPXLOPER FunctionFour( double, LPXLOPER ) {
const double pdData[2] = {41145., -0.01345212};
return XLReturn(pdData, 2, true);
}
問題を示すスプレッドシートは、上記のリンクで示されているパッケージに含まれています。
誰かが同様の振る舞いを見たことがありますか(はい、説明は非常に曖昧なので、言うのは難しいと思います...)?