次の方法で共有


Excel のメモリ管理

適用対象: Excel 2013 | Office 2013 | Visual Studio

効率的で安定した XLL を作成する場合は、メモリ管理が最も重要な懸念事項です。 メモリを適切に管理できないと、非効率的なメモリ割り当てや初期化、小さなメモリ リークなどの軽微な問題から、Excel の不安定化などの主要な問題まで、さまざまな問題が発生する可能性があります。

アドイン関連の深刻な問題の最も一般的な原因が、メモリ管理の失敗にあります。 したがって、プロジェクトをビルドする際、一貫性があり、十分に考慮したメモリ管理の戦略を使用する必要があります。

Microsoft Office Excel 2007 では、マルチスレッド ブックの再計算が導入され、メモリ管理がより複雑になりました。 スレッド セーフなワークシート関数を作成してエクスポートする場合は、複数のスレッドがアクセスに関して競合するときに生じる可能性がある競合状態を管理しなければなりません。

���� 3 �‚̃f�[�^�\���̌^�Ɋւ��郁�����̍l������������܂��B

  • XLOPER �� XLOPER12
  • XLOPER �ł� XLOPER12 �ł�Ȃ�������
  • FP �z��� FP12 �z��

XLOPER/XLOPER12 メモリ

XLOPER/ XLOPER12 データ構造には、メモリ ブロックへのポインター 、つまり文字列 (xltypeStr)、配列 (xltypeMulti)、外部参照 (xltypeRef) を含むいくつかのサブタイプがあります。 また、xltypeMulti 配列には、他のメモリ ブロックを指す文字列 XLOPER/ XLOPER12s を含めることもできます。

XLOPER/ XLOPER12 �́A���̂悤�ɂ����‚��̕��@�ō쐬����܂��B

  • Excel �ɂ���āBXLL �֐��ɓn�����������������Ƃ�
  • Excel �ɂ���āBC API �Ăяo���� XLOPER �܂��� XLOPER12 ���Ԃ����Ƃ�
  • DLL �ɂ���āBC API �Ăяo���ɓn����������쐬����Ƃ�
  • DLL によって。XLL 関数の戻り値を作成するとき

いずれかのメモリ ポイント型のメモリ ブロックは、次のいくつかの方法で割り当てることができます。

  • 関数コード外の DLL で静的ブロックとすることができます。この場合、メモリを割り当てたり解放したりする必要はありません。
  • �֐��R�[�h��� DLL �ŐÓI�u���b�N�Ƃ��邱�Ƃ��ł��܂��B���̏ꍇ�A����������蓖�Ă����������肷��K�v�͂���܂���B
  • DLL �œ��I�Ɋ��蓖�Ă�����������ł��܂��B���̂��߂ɂ́A malloc �� free�A new �� delete �Ȃǂ̕��@������܂��B
  • Excel �œ��I�Ɋ��蓖�Ă邱�Ƃ��ł��܂��B

XLOPER/ XLOPER12メモリの可能な配信元の数とXLOPER/ XLOPER12がそのメモリを割り当てた状況の数を考えると、この主題が非常に困難に見えることは驚くべきことではありません。 ただし、次に記すいくつかの規則とガイドラインに従うと、複雑さを大幅に削減できます。

XLOPER/XLOPER12 を扱うときの規則

  • XLL 関数に引数として渡される XLOPER/ XLOPER12s を解放したり上書きしたりしないでください。 そうした引数は読み取り専用にする必要があります。 詳細については、「Excel XLL 開発の既知の問題」の「引数をインプレースで変更して XLOPER またはXLOPER12を返す」を参照してください。

  • C API �ւ̌Ăяo���ŁADLL �ɕԂ���� XLOPER/ XLOPER12 �� Excel ������������蓖�Ă��ꍇ:

    • xlFree の呼び出しを使用して XLOPER/ XLOPER12 が不要になった場合はメモリを解放する必要があります。 その他の方法 (free、delete など) を使用してメモリを解放しないでください。
    • �Ԃ����^�� xltypeMulti �̂Ƃ��A�z���� XLOPER/ XLOPER12 ��㏑�����Ȃ��ł��������B���ɁA�����񂪊܂܂�Ă���ꍇ�A����ѕ�����ŏ㏑�����悤�Ƃ��Ă���̂ł͂Ȃ��ꍇ�ɒ��ӂ��Ă��������B
    • DLL �֐��̖߂�l�Ƃ��� XLOPER/ XLOPER12 �� Excel �ɕԂ��ꍇ�AExcel �ɑ΂��āA�s�v�ɂȂ�����������K�v�����郁���������݂��邱�Ƃ�ʒm���Ȃ���΂Ȃ�܂���B
  • C API 呼び出しへの戻り値として作成された XLOPER/ XLOPER12 でのみ xlFree を呼び出す必要があります。

  • DLL �֐��̖߂�l�Ƃ��� Excel �ɕԂ� XLOPER/ XLOPER12 �� DLL ������������蓖�Ă��ꍇ�ɂ́ADLL ���������K�v�����郁���������݂��邱�Ƃ� Excel �ɒʒm���Ȃ���΂Ȃ�܂���B

メモリ管理のガイドライン

  • メモリを割り当てて解放するために使用するメソッドを DLL 内で一貫させます。 異なるメソッドが混在しないようにします。 メモリ クラスまたは構造体で使用するメソッドをラップし、対象メソッドが使用されている多くの場所でコードを変えなくても変更できるようにすることをお勧めします。
  • DLL 内に xltypeMulti 配列を作成するときは、文字列にメモリを割り当てる方法で一貫性を保ち、常にそれらのメモリを動的に割り当てるか、または常に静的メモリを使用します。 これを行うと、メモリを解放するときに、文字列を常に解放するか解放しないかのどちらかが必要であることがわかります。
  • Excel ���쐬���� XLOPER/ XLOPER12 ��R�s�[����Ƃ��́AExcel �����蓖�Ă���������ڍ׃R�s�[���܂��B
  • Excel で割り当てられた文字列 XLOPER/ XLOPER12xltypeMulti 配列内に配置しないでください。 文字列の詳細コピーを作成し、そのコピーへのポインターを配列内に格納します。

Excel が割り当てた XLOPER/XLOPER12 メモリを解放する

���� XLL �R�}���h�ɂ‚��čl�����܂��B���̃R�}���h�́A xlGetName ��g�p���āADLL �̃p�X�ƃt�@�C������܂ޕ������擾���A xlcAlert ��g�p���Čx���_�C�A���O �{�b�N�X�ɕ\�����܂��B

int WINAPI show_DLL_name(void)
{
    XLOPER12 xDllName;
    if(Excel12(xlfGetName, &xDllName, 0) == xlretSuccess)
    {
        // Display the name.
        Excel12(xlcAlert, 0, 1, &xDllName);
        // Free the memory that Excel allocated for the string.
        Excel12(xlFree, 0, 1, &xDllName);
    }
    return 1;
}

���̊֐��� xDllName �ɂ���ă|�C���g����Ă��郁������K�v�Ƃ��Ȃ��Ȃ����Ȃ�ADLL ��p C API �֐��� 1 �‚ł��� xlFree �֐��ւ̌Ăяo����g�p���ĉ���ł��܂��B

xlFree �֐��ɂ‚��Ă͊֐����t�@�����X �Z�N�V���� (�u DLL �܂��� XLL ����̂݌Ăяo���”\�� C API �֐��v�������������) �ɏڍׂ��L����Ă��܂����A�ȉ��̓_�ɒ��ӂ��Ă��������B

  • xlFree の 1 回の呼び出しで複数の XLOPER/ XLOPER12へのポインターを渡すことができます。これは、実行中のバージョンの Excel でサポートされている関数引数の数 (Excel 2003 では 30、Excel 2007 以降では 255) によってのみ制限されます。
  • xlFree は、既に解放されている XLOPER/ XLOPER12 を解放しようとしても安全であることを確認するために包含ポインターを NULL に設定します。 xlFree は、引数を変更する唯一の C API 関数です。
  • メモリへのポインターが含まれているかどうかにかかわらずXLOPER12 C API への呼び出しの戻り値に使用される任意の XLOPER/ で xlFree を安全に呼び出すことができます。

Excel で解放される XLOPER/XLOPER12 を返す

前のセクションに記されているコマンド例を、Booleantrue 引数が渡されるときには DLL パスとファイル名を返し、それ以外の場合には #N/A を返すワークシート関数に変更する場合について考えます。 Excel に返される前に xlFree を呼び出して文字列メモリを解放できないことは明白です。 ただし、いずれかの時点で解放されないと、アドインは関数が呼び出されるたびにメモリ リークを起こします。 この問題を回避するには、xlcall.hxlbitXLFree として定義されている XLOPER/ XLOPER12xltype フィールドに少し設定します。 これを設定することによって、値のコピーが終了したときに、返されたメモリを解放する必要があることを Excel に通知します。

次のコード例は、XLL ワークシート関数に変換された、前のセクションの XLL コマンドを示しています。

LPXLOPER12 WINAPI get_DLL_name(int calculation_trigger)
{
    static XLOPER12 xRtnValue; // Not thread-safe
    Excel12(xlfGetName, &xRtnValue, 0);
// If xlfGetName failed, xRtnValue will be #VALUE!
    if(xRtnValue.xltype == xltypeStr)
    {
// Tell Excel to free the string memory after
// it has copied out the return value.
        xRtnValue.xltype |= xlbitXLFree;
    }
    return &xRtnValue;
}

XLOPER/ XLOPER12 s を使用する XLL 関数はXLOPER/ XLOPER12s へのポインターを取得して返すものとして宣言する必要があります。 この関数内で使用されているサンプルの静的 XLOPER12 はスレッド セーフではありません。 不適切にもこの関数をスレッド セーフとして登録することはできますが、あるスレッドが xRtnValue の処理を終了する前に別のスレッドが上書きしてしまうという危険が生じます。

xlbitXLFree の設定は、割り当てを行う Excel コールバックへの呼び出し後に行う必要があります。 設定を先に行うと、上書きされて、必要な動作が得られません。 別の C API 関数への呼び出しで値を引数として使用してからワークシートに戻す場合には、そのような呼び出し後にこのビットを設定してください。 それ以外の場合は、XLOPER/ XLLOPER12 型を確認する前にこのビットをマスクしない関数を混同します。

DLL で解放される XLOPER/XLOPER12 を返す

これと同様の問題は、XLL が XLOPER/ XLOPER12 にメモリを割り当てそれを Excel に返す場合に発生します。 Excel は、xlcall.hxlbitDLLFree として定義されている XLOPER/ XLOPER12xltype フィールドに設定できる別のビットを認識します。

When Excel receives an XLOPER/ XLOPER12 with this bit set, it tries to call a function that should be exported by the XLL called xlAutoFree (for XLOPERs) or xlAutoFree12 (for XLOPER12s). This function is described more fully in the function reference (see Add-in Manager and XLL Interface Functions), but an example minimal implementation is given here. Its purpose is to free the XLOPER/ XLOPER12 memory in a way that is consistent with how it was originally allocated.

���̊֐���́A�O�q�̊֐��Ɠ����ł��B��O�́ADLL ���̑O�ɁuThe full pathname for this DLL is�v�Ƃ����e�L�X�g���܂܂�Ă���_�ł��B

#include <string.h>
LPXLOPER12 WINAPI get_DLL_name_2(int calculation_trigger)
{
    static XLOPER12 xRtnValue; // Not thread-safe
    Excel12(xlfGetName, &xRtnValue, 0);
// If xlfGetName failed, xRtnValue will be #VALUE!
    if(xRtnValue.xltype != xltypeStr)
        return &xRtnValue;
// Make a copy of the DLL path and file name.
    wchar_t *leader = L"The full pathname for this DLL is ";
    size_t leader_len = wcslen(leader);
    size_t dllname_len = xRtnValue.val.str[0];
    size_t msg_len = leader_len + dllname_len;
    wchar_t *msg_text = (wchar_t *)malloc(msg_len + 1);
    wcsncpy_s(msg_text + 1, leader, leader_len);
    wcsncpy_s(msg_text + 1 + leader_len, xRtnValue.val.str + 1,
        dllname_len);
    msg_text[0] = msg_len;
// Now the original string has been copied Excel can free it.
    Excel12(xlFree, 0, 1, &xRtnValue);
// Now reuse the XLOPER12 for the new string.
    xRtnValue.val.str = msg_text;
// Tell Excel to call back into the DLL to free the string
// memory after it has copied out the return value.
    xRtnValue.xltype     = xltypeStr | xlbitDLLFree;
    return &xRtnValue;
}

�O�q�̊֐���G�N�X�|�[�g�����AXLL �ɂ����� xlAutoFree12 �̍ŏ����̎�������Ɏ����܂��B

void WINAPI xlAutoFree12(LPXLOPER12 p_oper)
{
    if(p_oper->xltype == (xltypeStr | xlbitDLLFree))
        free(p_oper->val.str);
}

この実装は、XLL が XLOPER12 文字列だけを戻し、それらの文字列を malloc のみを使用して割り当てる場合に限り使用できます。 次のテスト

if(p_oper->xltype == xltypeStr)

�͎��s���邱�Ƃɒ��ӂ��Ă��������B xlbitDLLFree ���ݒ肳��Ă��邽�߂ł�

��ʂɁA xlAutoFree �� xlAutoFree12 ��������AXLL �쐬�� xltypeMulti �z��� xltypeRef �O���Q�ƂɊ֘A���������������ł���悤�ɂ��Ȃ���΂Ȃ�܂���B

すべての場合に動的に割り当てられた XLOPERXLOPER12 を返すように XLL 関数を実装することもできます。 その場合、xlbitDLLFree を、サブタイプに関係なく、そうしたすべての XLOPERXLOPER12 で設定する必要があります。 また、xlAutoFree と xlAutoFree12 を実装して、このメモリが解放されるようにし、XLOPER/ XLOPER12 内で指すメモリも実装する必要があります。 これは、戻り値をスレッド セーフにする 1 つの方法です。 たとえば、前述の関数を次のように書き換えることができます。

#include <string.h>
LPXLOPER12 WINAPI get_DLL_name_3(int calculation_trigger)
{
// Thread-safe
    LPXLOPER12 pxRtnValue = (LPXLOPER12)malloc(sizeof(XLOPER12));
    Excel12(xlfGetName, pxRtnValue, 0);
// If xlfGetName failed, pxRtnValue will be #VALUE!
    if(pxRtnValue->xltype != xltypeStr)
    {
// Even though an error type does not point to memory,
// Excel needs to pass this oper to xlAutoFree12 to
// free pxRtnValue itself.
        pxRtnValue->xltype |= xlbitDLLFree;
        return pxRtnValue;
    }
// Make a copy of the DLL path and file name.
    wchar_t *leader = L"The full pathname for this DLL is ";
    size_t leader_len = wcslen(leader);
    size_t dllname_len = pxRtnValue->val.str[0];
    size_t msg_len = leader_len + dllname_len;
    wchar_t *msg_text = (wchar_t *)malloc(msg_len + 1);
    wcsncpy_s(msg_text + 1, leader, leader_len);
    wcsncpy_s(msg_text + 1 + leader_len, pxRtnValue->val.str + 1,
        dllname_len);
    msg_text[0] = msg_len;
// Now the original string has been copied Excel can free it.
    Excel12(xlFree, 0, 1, pxRtnValue);
// Now reuse the XLOPER12 for the new string.
    pxRtnValue->val.str = msg_text;
    pxRtnValue->xltype = xltypeStr | xlbitDLLFree;
    return pxRtnValue;
}
void WINAPI xlAutoFree12(LPXLOPER12 p_oper)
{
    if(p_oper->xltype == (xltypeStr | xlbitDLLFree))
        free(p_oper->val.str);
    free(p_oper);
}

xlAutoFree �� xlAutoFree12 �ɂ‚��ďڂ����́A�u xlAutoFree/xlAutoFree12�v��������������B

変更インプレース引数を返す

Excel では、XLL 関数はインプレースで引数を変更して値を返すことができます。 この操作は、ポインターとして渡された引数でのみ行うことができます。 このような処理を行うには、関数を登録するときに、変更対象の引数を Excel に通知しなければなりません。

この方法で値を返すことは、ポインターで渡すことができるすべてのデータ型でサポートされていますが、特に以下の型で便利です。

  • �������J�E���g����Anull �ŏI������ ASCII �o�C�g������
  • �������J�E���g����Anull �ŏI������ Unicode ���C�h���������� (Excel 2007 �ȍ~)
  • FP ���������_�z��
  • FP12 ���������_�z�� (Excel 2007 �ȍ~)

注:

この方法で、XLOPERXLOPER12 も返さないでください。 詳しくは、「Excel XLL 開発での既知の問題」をご覧ください。

The advantage of using this technique, instead of just using the return statement, is that Excel allocates the memory for the return values. Once Excel has finished reading the returned data, it releases the memory. This takes the memory management tasks away from the XLL function. This technique is thread safe: If called concurrently by Excel on different threads, each function call on each thread has its own buffer.

前述のデータ型に特に役立ちます。これは、XLOPER に存在するメモリの戻り後に解放するために DLL に呼び戻すメカニズム/ XLOPER12s は単純な文字列と FP/ FP12 配列には存在しないためです。 したがって、DLL で作成された文字列または浮動小数点配列を返す場合は、次の選択肢があります。

  • 永続的なポインターを動的に割り当てられたバッファーに設定し、ポインターを返します。 関数 (1) の次の呼び出しで、ポインターが null ではないことを確認し、(2) 前の呼び出しで割り当てられたリソースを解放し、ポインターを null にリセットし、(3) 新しく割り当てられたメモリ ブロックのポインターを再利用します。
  • ������Ɣz���A�������K�v���Ȃ��ÓI�o�b�t�@�[�ɍ쐬���A���̃o�b�t�@�[�ւ̃|�C���^�[��Ԃ��܂��B
  • ������C���v���[�X�ŕύX���܂��B���̍ہA������܂��͔z��� Excel �O�̗̈�ɒ��ڏ������݂܂��B

����ȊO�̕��@�Ń��\�[�X������[�X����ɂ́A XLOPER/ XLOPER12 ��쐬���A xlbitDLLFree �� xlAutoFree/ xlAutoFree12 ��g�p����K�v������܂��B

The last option might be the simplest in those cases in which you are being passed an argument of the same type as the return value. 銘記しておくべき重要なポイントは、バッファー サイズには制限があり、オーバーランしないように注意しなければならないという点です。 Getting this wrong could crash Excel. Buffer sizes for strings and FP/ FP12 arrays are discussed next.

文字列

文字列のメモリ管理に関する問題が、アプリケーションとアドインが不安定になる最も一般的な原因です。文字列を処理する方法 (null 終了または長さカウント (あるいはその両方)、静的バッファーまたは動的バッファー、固定長またはほぼ無制限の長さ、オペレーティング システム管理メモリ (たとえば、OLE Bstr など)、アンマネージ文字列など) が多様なことを考慮すると、これは理解できないことではありません。

C/C++ プログラマは、null 終了の文字列によく精通しています。 標準 C ライブラリは、このような文字列を処理するために設計されています。 コード内の静的文字列リテラルは、null 終了文字列にコンパイルされます。 また、Excel では、通常は null 終了ではない長さカウントの文字列を処理します。 こうした条件が組み合わされている状況では、文字列と文字列メモリを処理する方法に関して、DLL/XLL 内で明確かつ一貫性のある方法が必要となります。

�ł��ʓI�Ȗ���ȉ��Ɏ����܂��B

  • �L���ȃ|�C���^�[��K�v�Ƃ����̂̃|�C���^�[�̗L�������̂�`�F�b�N���Ȃ��܂��͂ł��Ȃ��֐��ɁAnull �܂��͖����ȃ|�C���^�[���n�����B
  • �������܂�镶����̒����ɑ΂��ăo�b�t�@�[�̒�����`�F�b�N���Ȃ��܂��͂ł��Ȃ��֐����A������o�b�t�@�[�̋��E��I�[�o�[��������B
  • 静的文字列バッファー メモリ、または既に解放された文字列バッファー メモリ、解放する方法と一貫しない方法で割り当てられた文字列バッファー メモリを解放しようとしている。
  • 割り当てられたものの解放されいない文字列から生じるメモリ リーク。通常、頻繁に呼び出される関数で生じます。

文字列の規則

XLOPER/ XLOPERと同様に、従う必要がある規則とガイドラインがあります。 ガイドラインは、前のセクションと同じです。 文字列用に特別に拡張された規則をここに記します。

�K��:

  • メモリを解放したり、 文字列 XLOPER/ XLOPER12または XLL 関数に引数として渡される単純な長さカウントまたは null で終わる文字列を上書きしないでください。 そうした引数は読み取り専用にする必要があります。
  • C API �R�[���o�b�N�֐��̖߂�l�̕����� XLOPER/ XLOPER12 �� Excel ������������蓖�Ă�ꍇ�A xlFree ��g�p���ĉ�����邩�AXLL �֐����� Excel �ɕԂ��ꍇ�ɂ� xlbitXLFree ��ݒ肵�Ă��������B
  • DLL �� XLOPER/ XLOPER12 �̕�����o�b�t�@�[�𓮓I�Ɋ��蓖�Ă�ꍇ�A���蓖�Ď��ƈ�т������@�ʼn�����邩�AXLL �֐����� Excel �ɕԂ����ꍇ�ɂ� xlbitDLLFree ��ݒ肵�Ă��� xlAutoFree/ xlAutoFree12 �ʼn�����܂��B
  • Excel で C API の呼び出しで DLL に返される xltypeMulti 配列のメモリが割り当てられている場合は、配列内の 文字列 XLOPER/ XLOPER12s を上書きしないでください。 このような配列は、 xlFree を使用してのみ解放する必要があります。または、xLL 関数によって返される場合は 、xlbitXLFree を設定します。

サポートされる文字列型

C API xltypeStr XLOPER/XLOPER12

バイト文字列: XLOPER ワイド文字列: XLOPER12
���ׂẴo�[�W������ Excel Excel 2007 �ȍ~
�ő咷:255 �g�� ASCII �o�C�g 最大長: 32,767 Unicode 文字
最初の (符号なし) バイト = 長さ 最初の Unicode 文字 = 長さ

重要

[!�D�V] XLOPER ������܂��� XLOPER12 ������ null �ŏI������Ƃ͑z�肵�Ȃ��ł��������B

C/C++ ������

�o�C�g������ ���C�h����������
Null 終了 (char *)"C" の最大長:255 拡張 ASCII バイト Null 終了 (wchar_t *) "C%" 最大長: 32,767 Unicode 文字
長さカウント (unsigned char *) "D" 長さカウント (wchar_t *) "D%"

xltypeMulti XLOPER/XLOPER12 配列内の文字列

場合によっては、Excel が、DLL/XLL で使用する xltypeMulti 配列を作成します。 XLM 情報機能の中には、そうした配列を返すものもあります。 たとえば、C API 関数 xlfGetWorkspace は、引数 44 が渡されると、現在登録されているすべての DLL プロシージャを記述する文字列を含む配列を返します。 C API 関数 xlfDialogBox は、配列の引数の変更済みコピー (文字列の詳細コピーを含みます) を返します。 XLL が xltypeMulti 配列に遭遇する最も一般的な場面は、XLL 関数に引数として渡す場合や、範囲参照からこの型に強制的にはめ込む場合です。 後者の場合、Excel はソース セルの文字列の詳細コピーを作成し、配列内でそれらをポイントします。

DLL でこうした文字列を変更する場合には、独自の詳細コピーを設定する必要がありjます。 独自の xltypeMulti 配列を作成するときは、Excel で割り当てられた文字列 XLOPER/ XLOPER12をそれらの中に配置しないでください。 配置すると、後ほど正しく解放できなかったり、まったく解放できなくなったりする恐れがあります。 もう一度、文字列の詳細コピーを作成し、配列内にそのコピーへのポインターを格納しなければなりません。

Examples

次の関数例は、長さカウントの Unicode 文字列の動的に割り当てられたコピーを作成します。 この例では、呼び出し元は、delete[] を使用して割り当てられたメモリを最終的に解放する必要があること、およびソース文字列は null 終了とは想定されていないことに注意してください。 コピー文字列は、安全のために必要であれば切り詰められ、null で終了しません。

#include <string.h>
#define MAX_V12_STRBUFFLEN    32678
    
wchar_t * deep_copy_wcs(const wchar_t *p_source)
{
    if(!p_source)
        return NULL;
    size_t source_len = p_source[0];
    bool truncated = false;
    if(source_len >= MAX_V12_STRBUFFLEN)
    {
        source_len = MAX_V12_STRBUFFLEN - 1; // Truncate the copy
        truncated = true;
    }
    wchar_t *p_copy = new wchar_t[source_len + 1];
    wcsncpy_s(p_copy, p_source, source_len + 1);
    if(truncated)
        p_copy[0] = source_len;
    return p_copy;
}

This function can then be safely used to copy an XLOPER12, as shown in the following exportable XLL function that returns a copy of its argument if it is a string. All other types are returned as a zero-length string. Note that ranges are not handled—the function returns #VALUE!. The function must be registered as taking a type U argument so that references are passed in as values. This is equivalent to the built-in worksheet function T() except that AsText also converts errors to zero-length strings. This code example assumes that xlAutoFree12 frees the passed-in pointer, and also its contents, using delete.

LPXLOPER12 WINAPI AsText(LPXLOPER12 pArg)
{
    LPXLOPER12 pRtnVal = new XLOPER12;
// If the input was an array, only operate on the top-left element.
    LPXLOPER *pTemp;
    if(pArg->xltype == xltypeMulti)
        pTemp = pArg->val.array.lparray;
    else
        pTemp = pArg;
    switch(pTemp->xltype)
    {
        case xltypeErr:
        case xltypeNum:
        case xltypeMissing:
        case xltypeNil:
        case xltypeBool:
            pRtnVal->xltype = xltypeStr | xlbitDLLFree;
            pRtnVal->val.str = deep_copy_wcs(L"\000");
            return pRtnVal;
        case xltypeStr:
            pRtnVal->xltype = xltypeStr | xlbitDLLFree;
            pRtnVal->val.str = deep_copy_wcs(pTemp->val.str);
            return pRtnVal;
        
        default: // xltypeSRef, xltypeRef, xltypeFlow, xltypeInt
            pRtnVal->xltype = xltypeErr | xlbitDLLFree;
            pRtnVal->val.err = xlerrValue;
            return pRtnVal;
    }
}

変更インプレース文字列引数を返す

FGF%G% 型として登録された引数は、インプレースで変更できます。 Excel はこれらの型の文字列引数を準備するときに、最大長のバッファーを作成します。 次に、対象文字列がかなり短い場合であっても、引数文字列をバッファーにコピーします。 このため、XLL 関数は同じメモリ内に戻り値を直接書き込むことができます。

こうした型のために取り分けられるバッファー サイズは次のとおりです。

  • バイト文字列:256 バイト (長さカウンター (G 型) または null 終端 (F 型) を含みます)。
  • Unicode 文字列:32,768 ワイド文字 (65,536 バイト)(長さカウンター (G% 型) または null 終端 (F% 型) を含みます)。

注:

十分に大きなバッファーが割り当てられていることを確認できないため、このような関数を Visual Basic for Applications (VBA) から直接呼び出すことはできません。 このような関数は、十分な大きさのバッファーを明示的に渡した場合にのみ、別の DLL から安全に呼び出すことができます。

標準ライブラリ関数 wcsrev を使用して、渡された null 終了のワイド文字を反転させる XLL 関数の例を次に示します。 この場合の引数は、型 F% として登録されます。

void WINAPI reverse_text_xl12(wchar_t *text)
{
    _wcsrev(text);
}

永続記憶 (バイナリ名)

Binary names are defined and associated with blocks of binary, that is, unstructured, data that is stored together with the workbook. They are created using the function xlDefineBinaryName, and the data is retrieved using the function xlGetBinaryName. どちらの関数も、関数リファレンスで詳しく説明されています (「 DLL または XLL からのみ呼び出すことができる C API 関数」を参照)、どちらも xltypeBigDataXLOPER/ XLOPER12 を使用します。

�o�C�i�����̎��ۂ̓K�p�𐧌�������m�̖��ɂ‚��ẮA�uExcel �A�h�C�� (XLL) �J���ɂ�������m�̖���v��������������B

Excel のスタック

Excel は、読み込んだすべての DLL とスタック領域を共有します。 通常、スタック領域は普段の使用量よりも多く、次に取り上げるいくつかのガイドラインに従う限りは問題となることはありません。

  • スタック上で、関数に対する引数としてとても大きな構造体を値として渡さないでください。 代わりに、ポインターや参照を渡します。
  • スタックに大きな構造体を返さないでください。 静的または動的に割り当てられたメモリへのポインターを返すか、参照によって渡される引数を使用します。
  • 関数コードで、非常に大規模な自動変数構造体を宣言しないでください。 必要な場合は、スタティック (Static) として宣言します。
  • 再帰の深さが浅いと分かっている以外は、関数を再帰的に呼び出さないでください。 代わりに、ループを使用します。

DLL が C API を使用して Excel に呼び出されると、最初に、最悪の場合の使用呼び出しに十分な領域がスタックに存在するかどうかを確認します。 空き容量が不足している可能性があると考えられる場合は、その特定の呼び出しに対して十分な空き領域が実際に存在していても、呼び出しが安全であると失敗します。 この場合、コールバックは コード xlretFailed を返します。 C API とスタックを通常使用する場合、これは C API 呼び出しの失敗の原因とは考えにくい原因です。

���̃G���[����������ꍇ�A�܂��͌��O����ꍇ�A���邢�͌����s���̃G���[���������Ƃ��ẴX�^�b�N�̈�̕s����������ꍇ�AxlStack �֐��ւ̌Ăяo���ŃX�^�b�N�̈悪�ǂ�قǂ��邩�𒲂ׂ邱�Ƃ��ł��܂��B

関連項目

Excel でのマルチスレッド再計算
Excel 2007 �ɂ�����}���`�X���b�h�����ƃ���������
Excel XLL �̊J��