Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Пишем библиотеку DLL для Metastock с нуля. Часть 3

Anna | 24.06.2014 | нет комментариев
В этой статье я объясню, как подключить к нашим индикаторам доводы (часть1часть2). За доводы в динамической библиотеке MSX DLL программы Metastock отвечают две служебные функции: MSXNthArg и MSXNthCustomString.

Доводы

MSXNthArg вызывается во время инициализации для всякого довода, всякой внешней функции, имеющей доводы.

BOOL __stdcall MSXNthArg (int a_iNthFunc,
						  int a_iNthArg,
						  MSXFuncArgDef *a_psFuncArgDef)

, где
• a_iNthFunc — индекс внешней функции.
• a_iNthArg — индекс довода этой функции.
• a_psFuncArgDef — Указатель на конструкцию данных MSXFuncArgDef, применяемой для заполнения пользователем информацией об доводе внешней функции.
Функция возвращает:
• MSX_SUCCESS если все верно и
• MSX_ERROR в случае ошибки.
Все доводы подразделяются на четыре типа:
• MSXDataArray — массив данных
• MSXNumeric — число,
• MSXString — строка,
• MSXCustom — custom.
При применении довода пользователь должен указать его тип и имя. Довод типа MSXCustom представляет собой определенный комплект, члены которого я буду называть custom-доводами. Если тип довода MSXCustom, тогда нужно еще указать число custom-доводов. То есть при изложении довода мы пишем в 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 отвечает за custom-доводы.

BOOL __stdcall MSXNthCustomString (int a_iNthFunc, 
								   int a_iNthArg,
                                   int a_iNthString, 
								   MSXFuncCustomString *a_psCustomString)

, где
• a_iNthFunc — индекс внешней функции.
• a_iNthArg — индекс довода этой функции.
• a_iNthString — индекс custom-довода.
• a_psFuncArgDef — Указатель на конструкцию данных MSXFuncCustomString, применяемой для заполнения пользователем информацией о custom-доводах внешней функции.
Функция возвращает те же значения, что и предыдущая.
Custom-довод представляет из себя пару: строка-идентификатор.Функция MSXNthCustomString устанавливает соответствие строки и числового идентификатора (ID). Во внешней функции custom-доводы вызываются по ID. Строки, используемые для определения custom-доводов, обязаны состоять только из алфавитно-цифровых символов. Пробелы и особые символы не допускаются. Custom-доводы не Эмоциональны к регистру.
число доводов всякого типа не может быть огромнее десяти. Не забывайте, что функции и доводы нумеруются с 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;
}

Для обработки исключений я добавил несколько дополнительных функций.

Пример

В дальнейшем ниже примере я сотворил четыре индикатора, которые занимаются сложением. У всякого индикатора два довода — один массив, а 2-й один из четырех типов. Как и обещал в первой части, расписал последовательность действий по шагам.
Создаем в Visual Studio план с тремя файлами: MSXStruc.h, Add.cpp, Add.def. Наша библиотека будет иметь имя 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; // один из 2-х доводов функции 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.

Код

// ----------------------------------------------------
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] = '';
  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 суммирует два массива данных (ExtFml( «Add.fan1», DA1, DA2)).
Функция имеет два довода, оба — массив данных.

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)).
Функция имеет два довода, один — массив данных, иной — число.

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)).
Функция имеет два довода, один — массив данных, иной — строка.

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 суммирует массив данных и массив данных определяемый custom-доводом
(ExtFml( «Add.fan4», DA1, DACust)).
Функция имеет два довода, один — массив данных, иной — довод типа 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

Верю, что в моих статьях мне удалось доступно высказать тезисы построения динамической библиотеки MSX DLL для программы Metastock.

 

Источник: programmingmaster.ru

 

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB