
この記事では、引数をインジケーター( part1 、 part2 )に接続する方法を説明します。 MetastockプログラムのMSXダイナミックライブラリDLLの引数には、MSXNthArgとMSXNthCustomStringの2つのユーティリティ関数があります。
引数
MSXNthArgは、各引数の初期化中に呼び出されます。各外部関数には引数があります。
BOOL __stdcall MSXNthArg (int a_iNthFunc, int a_iNthArg, MSXFuncArgDef *a_psFuncArgDef)
どこで
•a_iNthFunc-外部関数のインデックス。
•a_iNthArgは、この関数の引数のインデックスです。
•a_psFuncArgDef-ユーザーが外部関数の引数に関する情報を入力するために使用されるMSXFuncArgDefデータ構造へのポインター。
関数は以下を返します。
•すべてが正しく、MSX_SUCCESS
•エラーが発生した場合のMSX_ERROR。
すべての引数は4つのタイプに分けられます。
•MSXDataArray-データ配列
•MSXNumeric-番号、
•MSXString-文字列、
•MSXCustom-カスタム。
引数を使用する場合、ユーザーはそのタイプと名前を指定する必要があります。 MSXCustom型の引数は特定のセットであり、そのメンバーをカスタム引数と呼びます。 引数のタイプがMSXCustomの場合、カスタム引数の数も指定する必要があります。 つまり、引数を記述するときに、MSXNthArgに関数を記述します
非MSXCustomタイプの場合:
a_psFuncArgDef->iArgType = MSXDataArray; // MSXNumeric MSXString strcpy (a_psFuncArgDef->szArgName, " ");
MSXCustomタイプの場合:
a_psFuncArgDef->iArgType = MSXCustom; a_psFuncArgDef->iNCustomStrings = 8; // custom- strcpy (a_psFuncArgDef->szArgName, " ");
MSXNthCustomStringは、カスタム引数を担当します。
BOOL __stdcall MSXNthCustomString (int a_iNthFunc, int a_iNthArg, int a_iNthString, MSXFuncCustomString *a_psCustomString)
どこで
•a_iNthFunc-外部関数のインデックス。
•a_iNthArgは、この関数の引数のインデックスです。
•a_iNthString-カスタム引数のインデックス。
•a_psFuncArgDef-外部関数のカスタム引数に関する情報をユーザーに入力するために使用されるMSXFuncCustomStringデータ構造へのポインター。
この関数は、前のものと同じ値を返します。
カスタム引数は、文字列識別子のペアですMSXNthCustomString関数は、文字列と数値識別子(ID)の対応を設定します。 外部関数では、カスタム引数はIDによって呼び出されます。 カスタム引数の定義に使用される文字列は、英数字のみで構成する必要があります。 スペースと特殊文字は使用できません。 カスタム引数は大文字と小文字を区別しません。
各タイプの引数の数は10を超えることはできません。 関数と引数には0から番号が付けられることを忘れないでください。
例外
Metastockのクラッシュを回避するには、各外部関数に例外処理を追加する必要があります。 例外は次のとおりです。
•引数の数が無効です。
•着信(計算に使用)配列がMetastock標準に準拠していません(パート2を参照)
•引数を受け取っていない、
•引数が真ではない、
•出力(計算結果)配列がMetastock標準を満たしていません。
これらの各状況は、次の一般的な形式で処理します。
if ( , , ) { strncpy (a_psResult->szExtendedError, "Error: ", sizeof(a_psResult->szExtendedError)-1); // a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; }
例外を処理するために、いくつかの追加機能を追加しました。
例
次の例では、加算を処理する4つのインジケーターを作成しました。 各インジケータには2つの引数があります。1つは配列、もう1つは4つのタイプのうちの1つです。 前半で約束したように、一連のステップを描きました。
Visual Studioで、MSXStruc.h、Add.cpp、Add.defの3つのファイルでプロジェクトを作成します。 ライブラリの名前はAdd.dllになります。
ステップ1-ヘッダーとエクスポート
コード
#include <string.h> #include <stdlib.h> #include <math.h> #include <float.h> #include <tchar.h> #include "MSXStruc.h" #define DLL_EXPORT extern "C" __declspec(dllexport)
ステップ2-変更可能なパラメーター
ここには、ユーザーが変更可能な関数と引数のパラメーターがすべて登録されています。
コード
// const char *szMayCopyright ="VS 2010 C++ MSX DLL, Copyright (c) andrzwet, 2014"; const int MyFuncs = 4; // (fan1,fan2,fan3,fan4) // const char *szNfan1 = "fan1"; const char *szNfan2 = "fan2"; const char *szNfan3 = "fan3"; const char *szNfan4 = "fan4"; // const char *szDfan1 = "Add- (DA1 + DA2)"; const char *szDfan2 = "Add- (DA1 + Number)"; const char *szDfan3 = "Add- (DA1 + DAStr)"; const char *szDfan4 = "Add- (DA1 + DACust)"; const int fan1Args = 2; // 2 fan1 - 2 // fan1 const char *szNAfan1Arg1 = "DA1"; const char *szNAfan1Arg2 = "DA2"; const int fan2Args = 2; // 2 fan2 - 1 ,1 // fan2 const char *szNAfan2Arg1 = "DA1"; const char *szNNfan2Arg2 = "Numeric"; const int fan3Args = 2; // 2 fan3 - 1 ,1 // fan3 const char *szNAfan3Arg1 = "DA1"; const char *szNSfan3Arg2 = "DAStr"; const int fan4Args = 2; // 2 fan4 - 1 ,1 CustomType // fan4 const char *szNAfan4Arg1 = "DA1"; const char *szNCfan4Arg2 = "DACust"; const int fan4ArgsCust = 8; // fan4 Custom, // 8 () // custom- char *szCust1 = "Open"; char *szCust5 = "O"; int id1 = 0; char *szCust2 = "High"; char *szCust6 = "H"; int id2 = 1; char *szCust3 = "Low"; char *szCust7 = "L"; int id3 = 2; char *szCust4 = "Close"; char *szCust8 = "C"; int id4 = 3;
ステップ3-初期化関数
ここでは、MSXInfo、MSXNthFunction、MSXNthArg、MSXNthCustomStringの4つの関数について説明します。
コード
// ---------------------------------------------------- DLL_EXPORT BOOL __stdcall MSXInfo (MSXDLLDef *a_psDLLDef) { strncpy (a_psDLLDef->szCopyright, szMayCopyright, sizeof(a_psDLLDef->szCopyright)-1); a_psDLLDef->iNFuncs = MyFuncs; // . a_psDLLDef->iVersion = MSX_VERSION; return MSX_SUCCESS; } // ---------------------------------------------------- DLL_EXPORT BOOL __stdcall MSXNthFunction (int a_iNthFunc, MSXFuncDef *a_psFuncDef) { BOOL l_bRtrn = MSX_SUCCESS; switch (a_iNthFunc) { case 0: // --- fan1 --- strcpy (a_psFuncDef->szFunctionName, szNfan1); // strcpy (a_psFuncDef->szFunctionDescription, szDfan1); // a_psFuncDef->iNArguments = fan1Args; // break; case 1: // --- fan2 --- strcpy (a_psFuncDef->szFunctionName, szNfan2); // strcpy (a_psFuncDef->szFunctionDescription, szDfan2); // a_psFuncDef->iNArguments = fan2Args; // break; case 2: // --- fan3 --- strcpy (a_psFuncDef->szFunctionName, szNfan3); // strcpy (a_psFuncDef->szFunctionDescription, szDfan3); // a_psFuncDef->iNArguments = fan3Args; // break; case 3: // --- fan4 --- strcpy (a_psFuncDef->szFunctionName, szNfan4); // strcpy (a_psFuncDef->szFunctionDescription, szDfan4); // a_psFuncDef->iNArguments = fan4Args; // . break; default: l_bRtrn = MSX_ERROR; break; } return l_bRtrn; } // ---------------------------------------------------- DLL_EXPORT BOOL __stdcall MSXNthArg (int a_iNthFunc, int a_iNthArg, MSXFuncArgDef *a_psFuncArgDef) { BOOL l_bRtrn = MSX_SUCCESS; // custom- = 0 () a_psFuncArgDef->iNCustomStrings = 0; switch (a_iNthFunc) { case 0: // --- fan1 --- switch (a_iNthArg) { case 0: a_psFuncArgDef->iArgType = MSXDataArray; // strcpy (a_psFuncArgDef->szArgName, szNAfan1Arg1); // break; case 1: a_psFuncArgDef->iArgType = MSXDataArray; // strcpy (a_psFuncArgDef->szArgName, szNAfan1Arg2); // break; default: l_bRtrn = MSX_ERROR; break; } break; case 1: // --- fan2 --- switch (a_iNthArg) { case 0: a_psFuncArgDef->iArgType = MSXDataArray; // strcpy (a_psFuncArgDef->szArgName, szNAfan2Arg1); // break; case 1: a_psFuncArgDef->iArgType = MSXNumeric; // strcpy (a_psFuncArgDef->szArgName, szNNfan2Arg2); // break; default: l_bRtrn = MSX_ERROR; break; } break; case 2: // --- fan3 --- switch (a_iNthArg) { case 0: a_psFuncArgDef->iArgType = MSXDataArray; // strcpy (a_psFuncArgDef->szArgName, szNAfan3Arg1); // break; case 1: a_psFuncArgDef->iArgType = MSXString; // strcpy (a_psFuncArgDef->szArgName, szNSfan3Arg2); // break; default: l_bRtrn = MSX_ERROR; break; } break; case 3: // --- fan4 --- switch (a_iNthArg) { case 0: a_psFuncArgDef->iArgType = MSXDataArray; // strcpy (a_psFuncArgDef->szArgName, szNAfan4Arg1); // break; case 1: a_psFuncArgDef->iArgType = MSXCustom; // a_psFuncArgDef->iNCustomStrings = fan4ArgsCust; // - custom- strcpy (a_psFuncArgDef->szArgName, szNCfan4Arg2); // break; default: l_bRtrn = MSX_ERROR; break; } break; default: l_bRtrn = MSX_ERROR; break; } return l_bRtrn; } // ---------------------------------------------------- DLL_EXPORT BOOL __stdcall MSXNthCustomString (int a_iNthFunc, int a_iNthArg, int a_iNthString, MSXFuncCustomString *a_psCustomString) { BOOL l_bRtrn = MSX_SUCCESS; // a_psCustomString->szString[0] = '\0'; a_psCustomString->iID = -1; // typedef struct { char *szString; int iID; } LocalStringElement; // LocalStringElement l_sTheStrings[] = { {szCust1, id1}, {szCust5, id1}, {szCust2, id2}, {szCust6, id2}, {szCust3, id3}, {szCust7, id3}, {szCust4, id4}, {szCust8, id4} }; switch (a_iNthFunc) { case 3: // Custom- (fan4) switch (a_iNthArg) { case 1: // Custom- fan4 // Custom-. if(a_iNthString >= 0 && a_iNthString < fan4ArgsCust) { // ID strncpy (a_psCustomString->szString, l_sTheStrings[a_iNthString].szString, sizeof(a_psCustomString->szString)-1); a_psCustomString->iID = l_sTheStrings[a_iNthString].iID; } break; default: l_bRtrn = MSX_ERROR; break; } break; default: l_bRtrn = MSX_ERROR; break; } return l_bRtrn; }
ステップ4-追加機能
ここで、例外を処理するために必要な関数を書きます。
コード
/* ForceFloatRange - float . • FLT_MAX — , float (3.402823466e+38F), • FLT_MIN — , float (1.175494351e-38F). */ #define MSXMax(a,b) (((a) > (b)) ? (a) : (b)) #define MSXMin(a,b) (((a) < (b)) ? (a) : (b)) double ForceFloatRange (double a_lfDbl) { if (a_lfDbl > 0.0) { a_lfDbl = MSXMin (a_lfDbl, double(FLT_MAX)); a_lfDbl = MSXMax (a_lfDbl, double(FLT_MIN)); } else { if (a_lfDbl < 0.0) { a_lfDbl = MSXMax (a_lfDbl, double(-FLT_MAX)); a_lfDbl = MSXMin (a_lfDbl, double(-FLT_MIN)); } } return a_lfDbl; } /* MSXArray - MetaStock. MSXDataRec . , MSXDataRec. , , Metastock BasicData, . , , MetaStock'. */ BOOL MSXArray(const MSXDataRec *BasicData, const MSXDataInfoRec *ArgData) { if (ArgData->iFirstValid < 0) return FALSE; if (ArgData->iLastValid < 0) return FALSE; if (ArgData->iLastValid < ArgData->iFirstValid) return FALSE; if (ArgData->iFirstValid < BasicData->sClose.iFirstValid) return FALSE; if (ArgData->iLastValid > BasicData->sClose.iLastValid) return FALSE; return TRUE; }
ステップ5-外部機能
fan1は2つのデータ配列( ExtFml( "Add.fan1"、DA1、DA2) )を要約します。
この関数には2つの引数があり、両方ともデータの配列です。
fan1
DLL_EXPORT BOOL __stdcall fan1 (const MSXDataRec *a_psBasic, const MSXDataInfoRecArgsArray *a_psArrayArgs, const MSXNumericArgsArray *a_psNumericArgs, const MSXStringArgsArray *a_psStringArgs, const MSXCustomArgsArray *a_psCustomArgs, MSXResultRec *a_psResult) { int i = 0; // ( ) int iMinRecords = a_psBasic->sClose.iFirstValid; int iMaxRecords = a_psBasic->sClose.iLastValid; // const MSXDataInfoRec *l_psInput1 = a_psArrayArgs->psDataInfoRecs[0]; const MSXDataInfoRec *l_psInput2 = a_psArrayArgs->psDataInfoRecs[1]; int iLvi; int iFvi; // , if ( a_psArrayArgs->iNRecs == 2 && a_psNumericArgs->iNRecs == 0 && a_psStringArgs->iNRecs == 0 && a_psCustomArgs->iNRecs == 0) { if (!(MSXArray(a_psBasic, l_psInput1) && MSXArray(a_psBasic, l_psInput2) )) { // , strncpy (a_psResult->szExtendedError, "Error: Corrupted Input Array", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } // if (l_psInput1 && l_psInput2) { // fan1 for (i=iMinRecords; i<=iMaxRecords; i++) a_psResult->psResultArray->pfValue[i] = float (ForceFloatRange(l_psInput1->pfValue[i] + l_psInput2->pfValue[i])); // iFvi = MSXMax(l_psInput1->iFirstValid,l_psInput2->iFirstValid); iLvi = MSXMin(l_psInput1->iLastValid,l_psInput2->iLastValid); a_psResult->psResultArray->iFirstValid = iFvi; a_psResult->psResultArray->iLastValid = iLvi; } else { // ! strncpy (a_psResult->szExtendedError, "Error: Data array argument missing", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } } else { // ! strncpy (a_psResult->szExtendedError, "Error: Wrong number of arguments", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } if (!MSXArray(a_psBasic, a_psResult->psResultArray)) { // , strncpy (a_psResult->szExtendedError, "Error: Corrupted Result Array.", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } return MSX_SUCCESS; }
fan2は、データ配列と番号( ExtFml( "Add.fan2"、DA1、Numeric) )を要約します。
この関数には2つの引数があり、1つはデータ配列、もう1つは数値です。
fan2
DLL_EXPORT BOOL __stdcall fan2 (const MSXDataRec *a_psBasic, const MSXDataInfoRecArgsArray *a_psArrayArgs, const MSXNumericArgsArray *a_psNumericArgs, const MSXStringArgsArray *a_psStringArgs, const MSXCustomArgsArray *a_psCustomArgs, MSXResultRec *a_psResult) { int i = 0; // const MSXDataInfoRec *l_psInput = a_psArrayArgs->psDataInfoRecs[0]; // float l_fNumber = a_psNumericArgs->fNumerics[0]; // // , if ( a_psArrayArgs->iNRecs == 1 && a_psNumericArgs->iNRecs == 1 && a_psStringArgs->iNRecs == 0 && a_psCustomArgs->iNRecs == 0) { if (!MSXArray(a_psBasic, l_psInput)) { // strncpy (a_psResult->szExtendedError, "Error: Corrupted Input Array", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } // if (l_psInput) { // fan2 for (i=l_psInput->iFirstValid; i<=l_psInput->iLastValid; i++) a_psResult->psResultArray->pfValue[i] = float (ForceFloatRange(l_psInput->pfValue[i] + l_fNumber)); // a_psResult->psResultArray->iFirstValid = l_psInput->iFirstValid; a_psResult->psResultArray->iLastValid = l_psInput->iLastValid; } else { // ! strncpy (a_psResult->szExtendedError, "Error: Array argument missing", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } } else { // ! strncpy (a_psResult->szExtendedError, "Error: Wrong number of arguments", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } if (!MSXArray(a_psBasic, a_psResult->psResultArray)) { // , strncpy (a_psResult->szExtendedError, "Error: Corrupted Result Array", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } return MSX_SUCCESS; }
fan3は、文字配列で指定されたデータ配列とデータ配列を要約します
( ExtFml( "Add.fan3"、DA1、DAStr) )。
この関数には2つの引数があります。1つはデータ配列、もう1つは文字列です。
fan3
DLL_EXPORT BOOL __stdcall fan3 (const MSXDataRec *a_psBasic, const MSXDataInfoRecArgsArray *a_psArrayArgs, const MSXNumericArgsArray *a_psNumericArgs, const MSXStringArgsArray *a_psStringArgs, const MSXCustomArgsArray *a_psCustomArgs, MSXResultRec *a_psResult) { int i = 0; int iMinRecords = a_psBasic->sClose.iFirstValid; int iMaxRecords = a_psBasic->sClose.iLastValid; const MSXDataInfoRec *l_psInput1; l_psInput1 = a_psArrayArgs->psDataInfoRecs[0]; // const char *l_pszInput2 =a_psStringArgs->pszStrings[0]; // const MSXDataInfoRec *l_psData; int iLvi; int iFvi; // , if ( a_psArrayArgs->iNRecs == 1 && a_psNumericArgs->iNRecs == 0 && a_psStringArgs->iNRecs == 1 && a_psCustomArgs->iNRecs == 0) { if (!MSXArray(a_psBasic, l_psInput1)) { // strncpy (a_psResult->szExtendedError, "Error: Corrupted Input Array", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } // if (l_psInput1) { // if (l_pszInput2) { while (*l_pszInput2) { // switch (*l_pszInput2++) { case 'O': case 'o': l_psData = &a_psBasic->sOpen; break; case 'H': case 'h': l_psData = &a_psBasic->sHigh; break; case 'L': case 'l': l_psData = &a_psBasic->sLow; break; case 'C': case 'c': l_psData = &a_psBasic->sClose; break; default: // ! strncpy (a_psResult->szExtendedError, "Error: Wrong String argument", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; break; } // fan3 for (i=iMinRecords; i<=iMaxRecords; i++) a_psResult->psResultArray->pfValue[i] = float(ForceFloatRange( l_psData->pfValue[i] + l_psInput1->pfValue[i])); iFvi = MSXMax(l_psInput1->iFirstValid, l_psData->iFirstValid); iLvi = MSXMin(l_psInput1->iLastValid, l_psData->iLastValid); a_psResult->psResultArray->iFirstValid = iFvi; a_psResult->psResultArray->iLastValid = iLvi; } } else { // ! strncpy (a_psResult->szExtendedError, "Error: String argument missing", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } } else { // ! strncpy (a_psResult->szExtendedError, "Error: Array argument missing", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } } else { // ! strncpy (a_psResult->szExtendedError, "Error: Wrong number of arguments", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } if (!MSXArray(a_psBasic, a_psResult->psResultArray)) { strncpy (a_psResult->szExtendedError, "Error: Corrupted Result Array", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } return MSX_SUCCESS; }
fan4は、データ配列とカスタム引数で定義されたデータ配列を要約します
( ExtFml( "Add.fan4"、DA1、DACust) )。
この関数には2つの引数があり、1つはデータの配列、もう1つはMSXCustom型の引数です。
fan4
DLL_EXPORT BOOL __stdcall fan4 (const MSXDataRec *a_psBasic, const MSXDataInfoRecArgsArray *a_psArrayArgs, const MSXNumericArgsArray *a_psNumericArgs, const MSXStringArgsArray *a_psStringArgs, const MSXCustomArgsArray *a_psCustomArgs, MSXResultRec *a_psResult) { int i = 0; int iMinRecords = a_psBasic->sClose.iFirstValid; int iMaxRecords = a_psBasic->sClose.iLastValid; const MSXDataInfoRec *l_psInput1; l_psInput1 = a_psArrayArgs->psDataInfoRecs[0]; // int l_psInput2 = a_psCustomArgs->iCustomIDs[0]; // custom int iLvi; int iFvi; // , if ( a_psArrayArgs->iNRecs == 1 && a_psNumericArgs->iNRecs == 0 && a_psStringArgs->iNRecs == 0 && a_psCustomArgs->iNRecs == 1) { if (!(MSXArray(a_psBasic, l_psInput1) ) ) { strncpy (a_psResult->szExtendedError, "Error: Corrupted Input Array", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } // if (l_psInput1) { switch (l_psInput2) { case 0: // Open { for (i=iMinRecords; i<=iMaxRecords; i++) a_psResult->psResultArray->pfValue[i] = float(ForceFloatRange(a_psBasic->sOpen.pfValue[ i ] + l_psInput1->pfValue[i])); iLvi = MSXMin(l_psInput1->iLastValid,iMaxRecords); iFvi = MSXMax(l_psInput1->iFirstValid,iMinRecords); a_psResult->psResultArray->iFirstValid = iFvi; a_psResult->psResultArray->iLastValid = iLvi; } break; case 1: // High { for (i=iMinRecords; i<=iMaxRecords; i++) a_psResult->psResultArray->pfValue[i] = float(ForceFloatRange(a_psBasic->sHigh.pfValue[ i ] + l_psInput1->pfValue[i])); iLvi = MSXMin(l_psInput1->iLastValid,iMaxRecords); iFvi = MSXMax(l_psInput1->iFirstValid,iMinRecords); a_psResult->psResultArray->iFirstValid = iFvi; a_psResult->psResultArray->iLastValid = iLvi; } break; case 2: // Low { for (i=iMinRecords; i<=iMaxRecords; i++) a_psResult->psResultArray->pfValue[i] = float(ForceFloatRange(a_psBasic->sLow.pfValue[ i ] + l_psInput1->pfValue[i])); iLvi = MSXMin(l_psInput1->iLastValid,iMaxRecords); iFvi = MSXMax(l_psInput1->iFirstValid,iMinRecords); a_psResult->psResultArray->iFirstValid = iFvi; a_psResult->psResultArray->iLastValid = iLvi; } break; case 3: // Close { for (i=iMinRecords; i<=iMaxRecords; i++) a_psResult->psResultArray->pfValue[i] = float(ForceFloatRange(a_psBasic->sClose.pfValue[ i ] + l_psInput1->pfValue[i])); iLvi = MSXMin(l_psInput1->iLastValid,iMaxRecords); iFvi = MSXMax(l_psInput1->iFirstValid,iMinRecords); a_psResult->psResultArray->iFirstValid = iFvi; a_psResult->psResultArray->iLastValid = iLvi; } break; default: { // custom-! strncpy (a_psResult->szExtendedError, "Error: Invalid Custom argument", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } break; } } else { // ! strncpy (a_psResult->szExtendedError, "Error: Array argument missing", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } } else { // ! strncpy (a_psResult->szExtendedError, "Error: Wrong number of arguments", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } if (!MSXArray(a_psBasic, a_psResult->psResultArray)) { strncpy (a_psResult->szExtendedError, "Error: Corrupted Result Array", sizeof(a_psResult->szExtendedError)-1); a_psResult->psResultArray->iFirstValid = 0; a_psResult->psResultArray->iLastValid = -1; return MSX_ERROR; } return MSX_SUCCESS; }
ステップ6-DEFファイル
以下は私のプロジェクトのDEFファイルの例です。
DEFファイルは個別のテキストファイルであり、プロジェクトと同じ名前にする必要があります。
Add.def
LIBRARY Add EXPORTS MSXInfo MSXNthFunction MSXNthArg MSXNthCustomString fan1 fan2 fan3 fan4
私の記事で、Metastockプログラム用の動的MSX DLLをアクセシブルな方法で構築する原理を説明できたことを願っています。