しかし問題は、ネイティブAPIテクノロジーを使用する場合、外部コンポーネントと1C:Enterpriseの間で情報配列を交換するというかなり重要なタスクが発生することです。 記事へのコメントに正しく記載されているように、この問題は、プロシージャコールを繰り返すか、配列の内容をシリアル化することで解決する必要があります。
ただし、COMテクノロジを使用すると、すべてが大幅に簡素化されます。 実際のところ、1Cにはあまり知られていないが、この場合、COMSafeArrayなどのかけがえのないデータ型があります。
構文アシスタントからの抜粋:
COMSafeArray(COMSafeArray)
説明:
COMのSAFEARRAY多次元配列のオブジェクトラッパー。 SAFEARRAYを作成および使用して、COMオブジェクト間でデータを交換できます。
配列をCOMオブジェクトメソッドのパラメーターとして転送するには、目的の要素タイプで必要な次元のCOMSafeArrayを構築し、構築されたCOMSafeArrayを入力パラメーターの値として指定する必要があります。 その他1C:エンタープライズオブジェクトは、COMオブジェクトタイプのライブラリにパラメータータイプに関する包括的な情報がある場合にのみ、配列タイプの入力パラメーターとして使用できます。
COMオブジェクトメソッドの結果またはArray型の出力パラメーターの値は、常にCOMSafeArrayオブジェクトによって表されます。
説明:
COMのSAFEARRAY多次元配列のオブジェクトラッパー。 SAFEARRAYを作成および使用して、COMオブジェクト間でデータを交換できます。
配列をCOMオブジェクトメソッドのパラメーターとして転送するには、目的の要素タイプで必要な次元のCOMSafeArrayを構築し、構築されたCOMSafeArrayを入力パラメーターの値として指定する必要があります。 その他1C:エンタープライズオブジェクトは、COMオブジェクトタイプのライブラリにパラメータータイプに関する包括的な情報がある場合にのみ、配列タイプの入力パラメーターとして使用できます。
COMオブジェクトメソッドの結果またはArray型の出力パラメーターの値は、常にCOMSafeArrayオブジェクトによって表されます。
型自体の提供に加えて、COMSafeArray 1Cには、標準の1C配列をこの型の値に、またはその逆に変換できる包括的なメソッドセットが付属しています。
全体の秘trickは、このオブジェクトを外部コンポーネントの関数にパラメーターとして渡すと、COMテクノロジを使用して構築された外部コンポーネントで、この配列がSAFEARRAY型の配列へのポインターとして受け取られることです。
同様に、外部コンポーネントの関数からそのような配列へのポインターを返す場合、1Cでは、結果はCOMSafeArray型のオブジェクトとして解釈されます。
さらに、外部コンポーネントの関数では、入力配列自体、パラメーターとして受け取るポインターを変更でき、S_OKのみを関数から返すことができます。 1Cでは、その後、転送されたアレイの操作を続けることができ、外部コンポーネントによって生成された変更が含まれます。 つまり 1CとCOMコンポーネントの間で、参照渡しの通常のパラメーターを使用できます。
独自の例で示しましょう。
1Cでは、すべてを単純なボタンイベントに配置できます。
() // 1. = ; .(10.1); .(20.2); .(30.3); // COMSafeArray, double // 1. = COMSafeArray(, "VT_R8"); // . = 2.(); // 1 COMSafeArray. = .(); = .();
つまり COMSafeArray型のオブジェクトに基づいて作成され、その機能を外部コンポーネントに提供する通常の配列を作成して入力しました。
関数は何らかの方法で入力COMSafeArrayを変換し、COMSafeArrayの形式で何かを返します。
さらに、受信した両方のCOMSafeArrayオブジェクトを通常の1C配列にアンロードし、ビューアーで結果を確認します(Alt + F9)。
外部コンポーネントの側面では、すべてが少し複雑に見えます。 CallAsFunc関数にある対応するswitch-caseブロックでは、結果の配列を作成するだけでなく、入力配列自体も変更します。
実際、すべてはコメントに記述されています:
case arrayFunc: { // ********************************** // *** *** // ********************************** // SAFEARRAY // ( 1, ). long inputIdx = 0; void* inputVoidPtr = NULL; HRESULT hr = SafeArrayPtrOfIndex(*paParams, &inputIdx, &inputVoidPtr); // void* VARIANT* // (.. , VARIANT). VARIANT* inputVarPtr = (VARIANT*)inputVoidPtr; ///////////// . long iLowerBound; hr = SafeArrayGetLBound(inputVarPtr->parray, 1, &iLowerBound); if(FAILED(hr)) return S_FALSE; long iUpperBound; hr = SafeArrayGetUBound(inputVarPtr->parray, 1, &iUpperBound); if(FAILED(hr)) return S_FALSE; ////////////////////////////////////////////// void* sourcePtr = NULL; // , SafeArrayPtrOfIndex. double* sourceValPtr = NULL; // . for(long l = iLowerBound; l <= iUpperBound; l++) { // . hr = SafeArrayPtrOfIndex(inputVarPtr->parray, &l, &sourcePtr); // void* . sourceValPtr = (double*)sourcePtr; // () . ++(*sourceValPtr); } ///////////// ( ). // SAFEARRAYBOUND sBound[1]; sBound[0].cElements = iUBound - iLBound + 1; sBound[0].lLbound = 0; // , . VARTYPE varType; hr = SafeArrayGetVartype(sArr, &varType); if(FAILED(hr)) return S_FALSE; // . SAFEARRAY* sArrNew = SafeArrayCreate(varType, 1, sBound); ////////////////////////////////////////////// /////////// . // , SafeArrayPtrOfIndex. void* sourPtr = NULL; void* destPtr = NULL; // . for(long l = iLBound; l <= iUBound; l++) { // . hr = SafeArrayPtrOfIndex(sArr, &l, &sourPtr); hr = SafeArrayPtrOfIndex(sArrNew, &l, &destPtr); // void* // (, 2). *((double*)destPtr) = *((double*)sourPtr) * 2; } //////////////////////////////////////////// ///////////// . V_VT(pvarRetValue) = VT_ARRAY; V_ARRAY(pvarRetValue) = sArrNew; break; }
つまり 元の配列を取得し、何らかの方法で変更しました(この場合-増分)。
その後、同じ次元の新しい配列を作成し、特定の値(この場合、入力に2を掛けた値)を入力しました。
したがって、外部コンポーネントの機能を処理する前に配列があった場合:
パラメータの配列:{10.1、20.2、30.3}
この機能を実行すると、1Cで取得された配列は次の形式になります。
パラメータの配列:{11.1、21.2、31.3}
結果の配列:{22.2、42.4、62.6}
つまり そして、パラメータ配列と結果の配列は、外部コンポーネントの関数によって処理され、1Cで取得されました
変更された形式。
外部コンポーネントの完全な設計(デモ機能の拡張セットを含む)はこちらです。