MetaTraderプログラムを簡単かつ迅速に開発するためのライブラリ(第10部): プログラムリソースの作成と格納

Artyom Trishkin | 22 1月, 2020

内容

概念

アプリケーションを開発するとき、多くの場合、音声と画像が必要です。MQL言語には、このようなデータを使用するいくつかの方法がありますが、それらのすべてでは、ターミナルファイルサンドボックスからファイルをダウンロードする必要があります。最終結果がコンパイルされたファイルである場合、リソースとしてファイルを接続するだけで、プログラム操作に追加のファイルを渡す必要がなくなります。mql5.comマーケットで必要なのは実行可能ファイルのみなので、この方法はプログラムをmql5.comマーケットに送信するのに適しています。しかし、mql5.comコードベースには音声ファイル(*.wav)やグラフィカルファイル(*.bmp)は配置できないため、このメソッドはmql5.comコードベースにソースコードを配置するのには適していません。それらがなければ、ソースコードにはいくつかの重要な機能が欠けてしまいます。
ソリューションは非常に明白です。必要なすべてのファイルのデータをバイナリ配列として* .mqhインクルードファイルのソースコードに格納することです。アプリケーションを起動すると、必要なすべてのファイルが既存のデータセットから必要なディレクトリに生成されます。したがって、このようなコードを起動すると、アプリケーションは必要なファイルをすべて生成し、フォルダに配置して正常に動作します。これはすべて、ユーザーにとってシームレスに行われますが、唯一の例外は、存在しないファイルの生成と書き込みのために最初の起動時間がわずかに増加することです。

ファイルデータを使用するための2つのクラスを作成します。

ファイル生成クラスには、適切なデータからファイルを作成するための一連の静的メソッドがあります。これらのメソッドは、ライブラリのどの部分からでも使用できます。
既に生成されたファイルを使用するためのクラスには、作成されたすべてのファイルのリストと、リストに保存されたデータによってこれらのファイルにアクセスするためのメソッドが含まれます。実際、リストには作成されたファイルの簡単な記述(ファイル名と記述)が含まれます。このデータにより、物理ファイルに常にアクセスして使用できます。

ファイル生成クラス

Datas.mqhファイルから始めましょう。ここには、必要なメッセージを追加して、作成されたクラスの使用中に表示できます。

ライブラリテキストデータの配列内の新しいメッセージの場所をテキストメッセージインデックスの列挙に指定する定数を追加します。

//+------------------------------------------------------------------+
//| List of the library's text message indices                       |
//+------------------------------------------------------------------+
enum ENUM_MESSAGES_LIB
  {
   MSG_LIB_PARAMS_LIST_BEG=ERR_USER_ERROR_FIRST,      // Beginning of the parameter list
   MSG_LIB_PARAMS_LIST_END,                           // End of the parameter list
   MSG_LIB_PROP_NOT_SUPPORTED,                        // Property not supported
   MSG_LIB_PROP_NOT_SUPPORTED_MQL4,                   // Property not supported in MQL4
   MSG_LIB_PROP_NOT_SUPPORTED_POSITION,               // Property not supported for position
   MSG_LIB_PROP_NOT_SUPPORTED_PENDING,                // Property not supported for pending order
   MSG_LIB_PROP_NOT_SUPPORTED_MARKET,                 // Property not supported for market order
   MSG_LIB_PROP_NOT_SUPPORTED_MARKET_HIST,            // Property not supported for historical market order
   MSG_LIB_PROP_NOT_SET,                              // Value not set
   MSG_LIB_PROP_EMPTY,                                // Not set
   
   MSG_LIB_SYS_ERROR,                                 // Error
   MSG_LIB_SYS_NOT_SYMBOL_ON_SERVER,                  // Error. No such symbol on server
   MSG_LIB_SYS_FAILED_PUT_SYMBOL,                     // Failed to place to market watch. Error: 
   MSG_LIB_SYS_NOT_GET_PRICE,                         // Failed to get current prices. Error: 
   MSG_LIB_SYS_NOT_GET_MARGIN_RATES,                  // Failed to get margin ratios. Error: 
   MSG_LIB_SYS_NOT_GET_DATAS,                         // Failed to get data
   
   MSG_LIB_SYS_FAILED_CREATE_STORAGE_FOLDER,          // Failed to create folder for storing files. Error: 
   MSG_LIB_SYS_FAILED_ADD_ACC_OBJ_TO_LIST,            // Error. Failed to add current account object to collection list
   MSG_LIB_SYS_FAILED_CREATE_CURR_ACC_OBJ,            // Error. Failed to create account object with current account data
   MSG_LIB_SYS_FAILED_OPEN_FILE_FOR_WRITE,            // Could not open file for writing
   MSG_LIB_SYS_INPUT_ERROR_NO_SYMBOL,                 // Input error: no symbol
   MSG_LIB_SYS_FAILED_CREATE_SYM_OBJ,                 // Failed to create symbol object
   MSG_LIB_SYS_FAILED_ADD_SYM_OBJ,                    // Failed to add symbol
   
   MSG_LIB_SYS_NOT_GET_CURR_PRICES,                   // Failed to get current prices by event symbol
   MSG_LIB_SYS_EVENT_ALREADY_IN_LIST,                 // This event is already in the list
   MSG_LIB_SYS_FILE_RES_ALREADY_IN_LIST,              // This file already created and added to list:
   MSG_LIB_SYS_FAILED_CREATE_RES_LINK,                // Error. Failed to create object pointing to resource file
   MSG_LIB_SYS_ERROR_ALREADY_CREATED_COUNTER,         // Error. Counter with ID already created
   MSG_LIB_SYS_FAILED_CREATE_COUNTER,                 // Failed to create timer counter
   MSG_LIB_SYS_FAILED_CREATE_TEMP_LIST,               // Error creating temporary list
   MSG_LIB_SYS_ERROR_NOT_MARKET_LIST,                 // Error. This is not a market collection list
   MSG_LIB_SYS_ERROR_NOT_HISTORY_LIST,                // Error. This is not a history collection list
   MSG_LIB_SYS_FAILED_ADD_ORDER_TO_LIST,              // Could not add order to the list
   MSG_LIB_SYS_FAILED_ADD_DEAL_TO_LIST,               // Could not add deal to the list
   MSG_LIB_SYS_FAILED_ADD_CTRL_ORDER_TO_LIST,         // Failed to add control order
   MSG_LIB_SYS_FAILED_ADD_CTRL_POSITION_TO_LIST,      // Failed to add control position
   MSG_LIB_SYS_FAILED_ADD_MODIFIED_ORD_TO_LIST,       // Could not add modified order to the list of modified orders
    
   MSG_LIB_SYS_NO_TICKS_YET,                          // No ticks yet
   MSG_LIB_SYS_FAILED_CREATE_OBJ_STRUCT,              // Could not create object structure
   MSG_LIB_SYS_FAILED_WRITE_UARRAY_TO_FILE,           // Could not write uchar array to file
   MSG_LIB_SYS_FAILED_LOAD_UARRAY_FROM_FILE,          // Could not load uchar array from file
   MSG_LIB_SYS_FAILED_CREATE_OBJ_STRUCT_FROM_UARRAY,  // Could not create object structure from uchar array
   MSG_LIB_SYS_FAILED_SAVE_OBJ_STRUCT_TO_UARRAY,      // Failed to save object structure to uchar array, error
   MSG_LIB_SYS_ERROR_INDEX,                           // Error. "index" value should be within 0 - 3
   MSG_LIB_SYS_ERROR_FAILED_CONV_TO_LOWERCASE,        // Failed to convert string to lowercase, error
   
   MSG_LIB_SYS_ERROR_EMPTY_STRING,                    // Error. Predefined symbols string empty, to be used
   MSG_LIB_SYS_FAILED_PREPARING_SYMBOLS_ARRAY,        // Failed to prepare array of used symbols. Error 
   MSG_LIB_SYS_INVALID_ORDER_TYPE,                    // Invalid order type:
   


適切なインデックス定数に対応する英語とロシア語のテキストをテキストメッセージの配列に書き込みます。

//+------------------------------------------------------------------+
string messages_library[][TOTAL_LANG]=
  {
   {"Начало списка параметров","Beginning of the event parameter list"},
   {"Конец списка параметров","End of the parameter list"},
   {"Свойство не поддерживается","Property not supported"},
   {"Свойство не поддерживается в MQL4","Property not supported in MQL4"},
   {"Свойство не поддерживается у позиции","Property not supported for position"},
   {"Свойство не поддерживается у отложенного ордера","Property not supported for pending order"},
   {"Свойство не поддерживается у маркет-ордера","Property not supported for market order"},
   {"Свойство не поддерживается у исторического маркет-ордера","Property not supported for historical market order"},
   {"Значение не задано","Value not set"},
   {"Отсутствует","Not set"},
   
   {"Ошибка ","Error "},
   {"Ошибка. Такого символа нет на сервере","Error. No such symbol on server"},
   {"Не удалось поместить в обзор рынка. Ошибка: ","Failed to put in market watch. Error: "},
   {"Не удалось получить текущие цены. Ошибка: ","Could not get current prices. Error: "},
   {"Не удалось получить коэффициенты взимания маржи. Ошибка: ","Failed to get margin rates. Error: "},
   {"Не удалось получить данные ","Failed to get data of "},
   
   {"Не удалось создать папку хранения файлов. Ошибка: ","Could not create file storage folder. Error: "},
   {"Ошибка. Не удалось добавить текущий объект-аккаунт в список-коллекцию","Error. Failed to add current account object to collection list"},
   {"Ошибка. Не удалось создать объект-аккаунт с данными текущего счёта","Error. Failed to create account object with current account data"},
   {"Не удалось открыть для записи файл ","Could not open file for writing: "},
   {"Ошибка входных данных: нет символа ","Input error: no "},
   {"Не удалось создать объект-символ ","Failed to create symbol object "},
   {"Не удалось добавить символ ","Failed to add "},
   
   {"Не удалось получить текущие цены по символу события ","Failed to get current prices by event symbol "},
   {"Такое событие уже есть в списке","This event already in the list"},
   {"Такой файл уже создан и добавлен в список: ","This file has already been created and added to list: "},   
   {"Ошибка. Не удалось создать объект-указатель на файл ресурса","Error. Failed to create resource file link object"},
   
   {"Ошибка. Уже создан счётчик с идентификатором ","Error. Already created counter with id "},
   {"Не удалось создать счётчик таймера ","Failed to create timer counter "},
   
   {"Ошибка создания временного списка","Error creating temporary list"},
   {"Ошибка. Список не является списком рыночной коллекции","Error. The list is not a list of market collection"},
   {"Ошибка. Список не является списком исторической коллекции","Error. The list is not a list of history collection"},
   {"Не удалось добавить ордер в список","Could not add order to list"},
   {"Не удалось добавить сделку в список","Could not add deal to list"},
   {"Не удалось добавить контрольный ордер ","Failed to add control order "},
   {"Не удалось добавить контрольую позицию ","Failed to add control position "},
   {"Не удалось добавить модифицированный ордер в список изменённых ордеров","Could not add modified order to list of modified orders"},
   
   {"Ещё не было тиков","No ticks yet"},
   {"Не удалось создать структуру объекта","Could not create object structure"},
   {"Не удалось записать uchar-массив в файл","Could not write uchar array to file"},
   {"Не удалось загрузить uchar-массив из файла","Could not load uchar array from file"},
   {"Не удалось создать структуру объекта из uchar-массива","Could not create object structure from uchar array"},
   {"Не удалось сохранить структуру объекта в uchar-массив, ошибка ","Failed to save object structure to uchar array, error "},
   {"Ошибка. Значение \"index\" должно быть в пределах 0 - 3","Error. \"index\" value should be between 0 - 3"},
   {"Не удалось преобразовать строку в нижний регистр, ошибка ","Failed to convert string to lowercase, error "},
   
   {"Ошибка. Строка предопределённых символов пустая, будет использоваться ","Error. String of predefined symbols is empty, symbol will be used: "},
   {"Не удалось подготовить массив используемых символов. Ошибка ","Failed to create array of used characters. Error "},
   {"Неправильный тип ордера: ","Invalid order type: "},



配列内のテキストのシーケンスは、列挙内のインデックス定数の宣言のシーケンスと正確に一致する必要があることに注意してください。

ファイル生成クラスが機能するには、このクラスが音声ファイルと画像ファイルに関するデータを取得できるデータベースを作成する必要があります。このようなデータは、unsigned char配列の形式である必要があります。それらを作成するには、音声(*.wav)およびビットマップ(*.bmp)ファイルをライブラリソースに保存する必要があります。例として、いくつかのテストデータを既に準備しました。音声ファイルとビットマップファイルは、それぞれ独自のインクルードファイルに保存されます。

ライブラリの\MQL5\Include\DoEasy\ルートディレクトリでDataSND.mqhインクルードファイルを作成して、配列に配置される音声ファイルの名前を追加します(配列は16 MBを超えることができないので、データ配列名は特定のファイルのデータを使用して配列宣言場所をすばやく検索する場合にのみ必要です。データ配列名は後で追加できます)。

//+------------------------------------------------------------------+
//|                                                      DataSND.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
//+------------------------------------------------------------------+
//| Audio                                                            |
//+------------------------------------------------------------------+
/*
   sound_array_coin_01           // Falling coin 1
   sound_array_coin_02           // Falling coins
   sound_array_coin_03           // Coins
   sound_array_coin_04           // Falling coin 2
   //---
   sound_array_click_01          // Button click 1
   sound_array_click_02          // Button click 2
   sound_array_click_03          // Button click 3
   //---
   sound_array_cash_machine_01   // Cash register 1
*/
//+------------------------------------------------------------------+


プログラムのソースコードにファイルを挿入するには、EditInsert File as Binary Arrayの順にクリックします。


ファイル選択ウィンドウが開くので、事前に準備されたファイルを見つけてそのデータを配列にアップロードします。配列は、選択したファイルの名前に基づいて自動的に生成されます(バイナリデータが多数あるため、この例は完全ではありません)。

//+------------------------------------------------------------------+
//|                                                      DataSND.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
//+------------------------------------------------------------------+
//| Audio                                                            |
//+------------------------------------------------------------------+
/*
   sound_array_coin_01           // Falling coin 1
   sound_array_coin_02           // Falling coins
   sound_array_coin_03           // Coins
   sound_array_coin_04           // Falling coin 2
   //---
   sound_array_click_01          // Button click 1
   sound_array_click_02          // Button click 2
   sound_array_click_03          // Button click 3
   //---
   sound_array_cash_machine_01   // Cash register 1
*/
//+------------------------------------------------------------------+
//| Falling coin 01                                                  |
//+------------------------------------------------------------------+
unsigned char sound_array_coin_01[]=
  {
   0x52,0x49,0x46,0x46,0x1E,0x50,0x09,0x00,0x57,0x41,0x56,0x45,0x66,0x6D,0x74,0x20,
   0x12,0x00,0x00,0x00,0x03,0x00,0x02,0x00,0x44,0xAC,0x00,0x00,0x20,0x62,0x05,0x00,
   0x08,0x00,0x20,0x00,0x00,0x00,0x64,0x61,0x74,0x61,0x28,0x35,0x09,0x00,0x11,0xBA,
   0x20,0xBB,0x11,0xBA,0x20,0xBB,0x74,0x81,0x62,0xBB,0x74,0x81,0x62,0xBB,0xE9,0x37,
   0x4D,0xBB,0xE9,0x37,0x4D,0xBB,0x7C,0x41,0x13,0xBB,0x7C,0x41,0x13,0xBB,0x8F,0xE4,
   0x84,0xBA,0x8F,0xE4,0x84,0xBA,0x51,0x6D,0x05,0x3A,0x51,0x6D,0x05,0x3A,0xE1,0xC7,
   0x85,0x3A,0xE1,0xC7,0x85,0x3A,0xF5,0xA9,0xA1,0x39,0xF5,0xA9,0xA1,0x39,0xD6,0xF7,
   0x25,0xBA,0xD6,0xF7,0x25,0xBA,0x88,0x38,0x5B,0xBA,0x88,0x38,0x5B,0xBA,0xC8,0x31,
   0x05,0x39,0xC8,0x31,0x05,0x39,0x62,0xA0,0xF8,0x39,0x62,0xA0,0xF8,0x39,0x62,0xE5,
   0x39,0xBA,0x62,0xE5,0x39,0xBA,0x8A,0xAA,0x8B,0xBA,0x8A,0xAA,0x8B,0xBA,0xDC,0xF9,
   0x0B,0xBA,0xDC,0xF9,0x0B,0xBA,0xEA,0x27,0x97,0xBA,0xEA,0x27,0x97,0xBA,0xA1,0x5E,
   0xDA,0xBA,0xA1,0x5E,0xDA,0xBA,0x96,0x5B,0x56,0xBA,0x96,0x5B,0x56,0xBA,0x13,0xB9,
   0xA6,0xB8,0x13,0xB9,0xA6,0xB8,0x3B,0xFD,0x39,0xB7,0x3B,0xFD,0x39,0xB7,0x05,0x39,
   0x37,0xB9,0x05,0x39,0x37,0xB9,0x7D,0xED,0x18,0xBA,0x7D,0xED,0x18,0xBA,0x73,0xDD,
   0x8A,0xBA,0x73,0xDD,0x8A,0xBA,0xD1,0x83,0xD4,0xBA,0xD1,0x83,0xD4,0xBA,0xFF,0x94,
   0x0C,0xBB,0xFF,0x94,0x0C,0xBB,0xAF,0x13,0xF6,0xBA,0xAF,0x13,0xF6,0xBA,0x5A,0x27,
   0x4A,0xBA,0x5A,0x27,0x4A,0xBA,0x68,0xA7,0xA1,0x39,0x68,0xA7,0xA1,0x39,0xBE,0x9B,
   0x32,0x3A,0xBE,0x9B,0x32,0x3A,0xFD,0x21,0x0C,0x3A,0xFD,0x21,0x0C,0x3A,0x36,0xFF,
   0x21,0x3A,0x36,0xFF,0x21,0x3A,0xB5,0xA2,0x36,0x3A,0xB5,0xA2,0x36,0x3A,0xBB,0x73,
   0xE2,0xB9,0xBB,0x73,0xE2,0xB9,0x16,0xDA,0x16,0xBB,0x16,0xDA,0x16,0xBB,0x41,0x70,
   0x23,0xBB,0x41,0x70,0x23,0xBB,0xA9,0xC6,0x34,0xBA,0xA9,0xC6,0x34,0xBA,0x78,0x88,
   0x35,0x37,0x78,0x88,0x35,0x37,0xFB,0x4C,0xA9,0xBA,0xFB,0x4C,0xA9,0xBA,0xDA,0xAA,


配列データはファイルの配列を完全に繰り返すため、結果の配列は非常に大きくなります。これが、Ctrl+Fを使用してリスト内の各配列の先頭にすばやくジャンプするために、作成した配列の名前を事前に入力した理由です。

これで、必要な数の音声データ配列をファイルリストに追加するだけです。すでにいくつかのテスト音声を作成しています。ファイルが大きいため、ここに記載しても意味がありません。以下に添付されているライブラリファイルでご覧になれます。

まったく同じ方法で、ビットマップデータを含むDataIMG.mqhという名前のファイルを作成します。このファイルは、2色のLED電球を表す2つの配列(1つの緑のLEDの画像と別の赤のLEDの画像を含むデータ)を既に作成しています。

//+------------------------------------------------------------------+
//|                                                      DataIMG.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
//+------------------------------------------------------------------+
//| Images                                                           |
//+------------------------------------------------------------------+
/*
   img_array_spot_green             // Green LED 16x16, 32 bit
   img_array_spot_red               // Red LED 16x16, 32 bit
*/
//+------------------------------------------------------------------+
//| Green LED 32 bit, alpha                                          |
//+------------------------------------------------------------------+
unsigned char img_array_spot_green[]=
  {
   0x42,0x4D,0x38,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x28,0x00,
   0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x20,0x00,0x00,0x00,
   0x00,0x00,0x02,0x04,0x00,0x00,0xC3,0x0E,0x00,0x00,0xC3,0x0E,0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
   0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
   0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
   0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
   0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
   0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,


...

   0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
   0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
   0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
   0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
   0xFF,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00
  };
//+------------------------------------------------------------------+
//| Red LED 32 bit, alpha                                            |
//+------------------------------------------------------------------+
unsigned char img_array_spot_red[]=
  {
   0x42,0x4D,0x38,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x28,0x00,
   0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x20,0x00,0x00,0x00,
   0x00,0x00,0x02,0x04,0x00,0x00,0xC3,0x0E,0x00,0x00,0xC3,0x0E,0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
   0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
   0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
   0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
   0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,


音声データを使用した例のように、ここでは結果ファイルを完全に記載することはしません。

Defines.mqhファイルにデータを含むファイルをインクルードして、ファイルのバイナリデータがライブラリで利用できるようにします。

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
//+------------------------------------------------------------------+
//| ファイルをインクルードする                                                    |
//+------------------------------------------------------------------+
#include "DataSND.mqh"
#include "DataIMG.mqh"
#include "Datas.mqh"
#ifdef __MQL4__
#include "ToMQL4.mqh"
#endif 
//+------------------------------------------------------------------+


Defines.mqhファイルのマクロ置き換えブロックにライブラリリソースデータの場所フォルダーを指定するマクロ置き換えを追加します。

//+------------------------------------------------------------------+
//| マクロ置換                                              |
//+------------------------------------------------------------------+
//--- Describe the function with the error line number
#define DFUN_ERR_LINE                  (__FUNCTION__+(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian" ? ", Page " : ", Line ")+(string)__LINE__+": ")
#define DFUN                           (__FUNCTION__+": ")        // "Function description"
#define COUNTRY_LANG                   ("Russian")                // Country language
#define END_TIME                       (D'31.12.3000 23:59:59')   // End date for account history data requests
#define TIMER_FREQUENCY                (16)                       // Minimal frequency of the library timer in milliseconds
//--- Parameters of the orders and deals collection timer
#define COLLECTION_ORD_PAUSE           (250)                      // Orders and deals collection timer pause in milliseconds
#define COLLECTION_ORD_COUNTER_STEP    (16)                       // Increment of the orders and deals collection timer counter
#define COLLECTION_ORD_COUNTER_ID      (1)                        // Orders and deals collection timer counter ID
//--- Parameters of the account collection timer
#define COLLECTION_ACC_PAUSE           (1000)                     // Account collection timer pause in milliseconds
#define COLLECTION_ACC_COUNTER_STEP    (16)                       // Account timer counter increment
#define COLLECTION_ACC_COUNTER_ID      (2)                        // Account timer counter ID
//--- Symbol collection timer 1 parameters
#define COLLECTION_SYM_PAUSE1          (100)                      // Pause of the symbol collection timer 1 in milliseconds (for scanning market watch symbols)
#define COLLECTION_SYM_COUNTER_STEP1   (16)                       // Increment of the symbol timer 1 counter
#define COLLECTION_SYM_COUNTER_ID1     (3)                        // Symbol timer 1 counter ID
//--- Symbol collection timer 2 parameters
#define COLLECTION_SYM_PAUSE2          (300)                      // Pause of the symbol collection timer 2 in milliseconds (for events of the market watch symbol list)
#define COLLECTION_SYM_COUNTER_STEP2   (16)                       // Increment of the symbol timer 2 counter
#define COLLECTION_SYM_COUNTER_ID2     (4)                        // Symbol timer 2 counter ID
//--- Collection list IDs
#define COLLECTION_HISTORY_ID          (0x7779)                   // Historical collection list ID
#define COLLECTION_MARKET_ID           (0x777A)                   // Market collection list ID
#define COLLECTION_EVENTS_ID           (0x777B)                   // Event collection list ID
#define COLLECTION_ACCOUNT_ID          (0x777C)                   // Account collection list ID
#define COLLECTION_SYMBOLS_ID          (0x777D)                   // Symbol collection list ID
//--- Data parameters for file operations
#define DIRECTORY                      ("DoEasy\\")               // Library directory for storing object folders
#define RESOURCE_DIR                   ("DoEasy\\Resource\\")     // Library directory for storing resource folders
//--- Symbol parameters
#define CLR_DEFAULT                    (0xFF000000)               // Default color
#define SYMBOLS_COMMON_TOTAL           (1000)                     // Total number of working symbols
//+------------------------------------------------------------------+


Resource\ライブラリサブフォルダでは、それぞれ音声および画像ファイルを作成および保存するためのSoundsおよびImagesフォルダが自動的に生成されます。

準備された配列からファイルを作成する場合、拡張子を指定する必要があります。どのファイルが正確に作成され、どのフォルダに配置されるべきかをファイル生成メソッドに知らせるために、データがバイナリ配列に書き込まれるファイルタイプの列挙が必要です。
Defines.mqhの最後に必要な列挙を追加します。

//+------------------------------------------------------------------+
//| Data for working with program resource data                      |
//+------------------------------------------------------------------+
enum ENUM_FILE_TYPE
  {
   FILE_TYPE_WAV,                                           // wav file
   FILE_TYPE_BMP,                                           // bmp file
  };
//+------------------------------------------------------------------+


すべてのライブラリリソースファイルはターミナルのMQL5\Files\のSoundsおよびImagesフォルダにあるため、CMessageクラスのPlaySound()メソッドを修正する必要があります。\MQL5\Include\DoEasy\Services\Message.mqhを開いてPlaySound()メソッドファイルパスを調整します

//+------------------------------------------------------------------+
//| Play an audio file                                               |
//+------------------------------------------------------------------+
bool CMessage::PlaySound(const string file_name)
  {
   bool res=::PlaySound("\\Files\\"+file_name);
   CMessage::m_global_error=(res ? ERR_SUCCESS : ::GetLastError());
   return res;
  }
//+------------------------------------------------------------------+


ファイルを再生するには\Files\サブフォルダを指定します。これは、すべてのデータがMQL5\およびこのフォルダに相対して保存されるためです。一方、残りのファイルパスは、ファイル記述オブジェクトの作成時にfile_nameパラメータを使用して設定され、メソッドに渡されます。

現在、必要なクラスを作成するにはこれで十分です。

\MQL5\Include\DoEasy\Services\で、新しいCFileGenクラスをFileGen.mqhファイルに作成します。

//+------------------------------------------------------------------+
//|                                                      FileGen.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| ファイルをインクルードする                                                    |
//+------------------------------------------------------------------+
#include "..\\Services\DELib.mqh"
//+------------------------------------------------------------------+
//| File generator class                                             |
//+------------------------------------------------------------------+
class CFileGen
  {
private:
   static string     m_folder_name;    // Name of a folder library resource files are stored in
   static string     m_subfolder;      // Name of a subfolder storing audio or bitmap files
   static string     m_name;           // File name
   static int        m_handle;         // File handle
//--- Set a (1) file, (2) subfolder name
   static void       SetName(const ENUM_FILE_TYPE file_type,const string file_name);
   static void       SetSubFolder(const ENUM_FILE_TYPE file_type);
//--- Return file extension by its type
   static string     Extension(const ENUM_FILE_TYPE file_type);
public:
//--- Return the (1) set name, (2) the flag of a file presence in the resource directory
   static string     Name(void)  { return CFileGen::m_name; }
   static bool       IsExist(const ENUM_FILE_TYPE file_type,const string file_name);
//--- Create a file out of the data array
   static bool       Create(const ENUM_FILE_TYPE file_type,const string file_name,const uchar &file_data_array[]);
  };
//+------------------------------------------------------------------+


クラスの使用に必要なDefines.mqhおよびMessage.mqhは既にインクルードされているため、ファイルにすぐにサービス関数のDELib.mqhライブラリをインクルードします

//+------------------------------------------------------------------+
//|                                                        DELib.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property strict  // mql4に必要
//+------------------------------------------------------------------+
//| ファイルをインクルードする                                                    |
//+------------------------------------------------------------------+
#include "..\Defines.mqh"
#include "Message.mqh"
#include "TimerCounter.mqh"
//+------------------------------------------------------------------+


すべてのクラスメンバ変数とそのメソッドにはコードにヘッダがあるのですべてが明確になっています。それらの目的を説明する意味はありません。メソッドの実装を考えてみましょう。
クラスメンバ変数は静的なので、明確な初期化が必要です。

//+------------------------------------------------------------------+
//| Initialization of static variables                               |
//+------------------------------------------------------------------+
string CFileGen::m_folder_name=RESOURCE_DIR;
string CFileGen::m_subfolder="\\";
string CFileGen::m_name=NULL;
int    CFileGen::m_handle=INVALID_HANDLE;
//+------------------------------------------------------------------+


以下は、データ配列からファイルを作成するメソッドです。

//+------------------------------------------------------------------+
//| Create a file out of a data array                                |
//+------------------------------------------------------------------+
bool CFileGen::Create(const ENUM_FILE_TYPE file_type,const string file_name,const uchar &file_data_array[])
  {
   //--- Set a file name consisting of the file path, its name and extension
   CFileGen::SetName(file_type,file_name);
   //--- If such a file already exists, return 'false'
   if(::FileIsExist(CFileGen::m_name))
      return false;
   //--- Open the file with the generated name for writing
   CFileGen::m_handle=::FileOpen(CFileGen::m_name,FILE_WRITE|FILE_BIN);
   //--- If failed to create the file, receive an error code, display the file opening error message and return 'false'
   if(CFileGen::m_handle==INVALID_HANDLE)
     {
      int err=::GetLastError();
      ::Print(CMessage::Text(MSG_LIB_SYS_FAILED_OPEN_FILE_FOR_WRITE),"\"",CFileGen::m_name,"\". ",CMessage::Text(MSG_LIB_SYS_ERROR),"\"",CMessage::Text(err),"\" ",CMessage::Retcode(err));
      return false;
     }
   //--- Write the contents of the file_data_array[] array, close the file and return 'true'

   ::FileWriteArray(CFileGen::m_handle,file_data_array);
   ::FileClose(CFileGen::m_handle);
   return true;
  }
//+------------------------------------------------------------------+


このメソッドは、標準的なファイル関数FileWriteArray()を使用して、文字列1を除く任意のデータの配列をバイナリファイルに書き込むことができます。
このメソッドは、書き込まれたファイルの種類(音声または画像)、将来のファイルの名前、作成されたファイルのバイナリデータのセットを含む配列を受け取ります 。
メソッドによって実行されるすべてのアクションは、コードに記載されており、単純でわかりやすいものです。ここで説明する必要はありません。

以下は、リソースディレクトリにファイルが存在するかどうかのフラグを返すメソッドです。

//+------------------------------------------------------------------+
//| The flag of a file presence in the resource directory            |
//+------------------------------------------------------------------+
bool CFileGen::IsExist(const ENUM_FILE_TYPE file_type,const string file_name)
  {
   CFileGen::SetName(file_type,file_name);
   return ::FileIsExist(CFileGen::m_name);
  }
//+------------------------------------------------------------------+


メソッドは、書き込まれたファイルの種類と、存在を確認する必要があるファイルの名前を受け取ります。次に、ファイルパス、名前、拡張子で構成されるファイル名が設定され、FileIsExist()関数を使用して同じ名前のファイルが存在を確認した結果が返されます。

以下は、ファイルパス、名前、拡張子で構成されるファイル名を設定するメソッドです。

//+------------------------------------------------------------------+
//| Set a file name                                                  |
//+------------------------------------------------------------------+
void CFileGen::SetName(const ENUM_FILE_TYPE file_type,const string file_name)
  {
   CFileGen::SetSubFolder(file_type);
   CFileGen::m_name=CFileGen::m_folder_name+CFileGen::m_subfolder+file_name+CFileGen::Extension(file_type);
  }
//+------------------------------------------------------------------+


このメソッドは、書き込まれたファイルの種類ファイル名を受け取ります。メソッドは、ライブラリファイルを保存するフォルダname ( file_name)メソッドに渡されるSetSubFolder()メソッドによって作成されたファイル拡張子サブフォルダExtension()メソッドによってファイルの種類で作成されたファイル拡張子 (音声またはイメージ)を含む完全なファイル名を組み立てます。 得られた結果は、m_nameクラスメンバ変数に書き込まれます。

以下は、ファイルの種類(音声または画像)に応じてサブフォルダ名を設定するメソッドです。

//+------------------------------------------------------------------+
//| Set a subfolder name                                             |
//+------------------------------------------------------------------+
void CFileGen::SetSubFolder(const ENUM_FILE_TYPE file_type)
  {
   CFileGen::m_subfolder=(file_type==FILE_TYPE_BMP ? "Images\\" : file_type==FILE_TYPE_WAV ? "Sounds\\" : "");
  }
//+------------------------------------------------------------------+


メソッドはファイルの種類を受け取ります。そのタイプに基づいて、m_subfolder クラスメンバ変数はImages\またはSounds\サブフォルダ名を受け取ります。

以下は、種類ごとにファイル拡張子を返すメソッドです。

//+------------------------------------------------------------------+
//| Return file extension by its type                                |
//+------------------------------------------------------------------+
string CFileGen::Extension(const ENUM_FILE_TYPE file_type)
  {
   string ext=::StringSubstr(::EnumToString(file_type),10);
   if(!::StringToLower(ext))
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_CONV_TO_LOWERCASE),CMessage::Retcode(::GetLastError()));
   return "."+ext;
  }
//+------------------------------------------------------------------+


メソッドはファイルの種類を受け取ります。 次に、メソッドに渡されたENUM_FILE_TYPE列挙定数のテキスト表現(EnumToString())から、StringSubstr()関数を使用して拡張子を取得します (音声ファイルの場合、「FILE_TYPE_WAV」文字列から「WAV」部分文字列が取得され、 ビットマップファイルの場合は「BMP」です)。 次に、ファイル拡張子を持つ取得された部分文字列のすべてのシンボルがStringToLower()を使用して文字列に変換され、th「フルストップ」文字(.)が文字列(その前)に追加され、取得された結果がメソッドから返されます

これで、ファイル生成クラスの作成は終了です。

これで、ソースコードに任意の音声ファイルとビットマップファイルのバイナリデータを保存し、プログラムの起動中にこのデータから本格的なファイルを自動的に作成できます。ファイルは適切なフォルダに配置され、ライブラリはファイルにアクセスして意図した目的に使用します。
ファイルに便利にアクセスするには、何らかの方法で既存のファイルを記述し、それらにすばやく簡単にアクセスできる必要があります。これを行うには、プログラムリソースコレクションクラスを作成します。これは、ライブラリ(コレクションオブジェクトへのポインタのリスト)で作成するコレクションではなく、ファイル記述オブジェクトのコレクションになります。
それぞれの作成された物理ファイルを説明するオブジェクトを生成して、名前、パス、記述を指定します。物理ファイルには、これらの記述子オブジェクトを使用してアクセスします。ファイルの記述は、特定のファイルごとに記述子オブジェクトに追加するテキスト記述で構成されます。
例えば、マウスクリックの音は、「マウスクリック01」、「クリック01」など好きに記述できます。必要なファイルの記述子を取得するには、検索パラメータに記述を入力するだけです。検索メソッドは、物理ファイルのプロパティを取得するために使用できるファイル記述子オブジェクトインデックスを返します。

プログラムリソースコレクションクラス

\MQL5\Include\DoEasy\Collections\ライブラリフォルダで、新しいCResourceCollectionクラスをResourceCollection.mqhファイルで作成します。新しいクラスのコードで、さらに別のクラスを記述します。これは、新しいオブジェクトごとにインスタンスが作成され、記述子コレクションに追加される記述子オブジェクトクラスです。

//+------------------------------------------------------------------+
//|                                           ResourceCollection.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| ファイルをインクルードする                                                    |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
#include "..\\Services\\FileGen.mqh"
//+------------------------------------------------------------------+
//| Descriptor object class for the library resource file            |
//+------------------------------------------------------------------+
class CResObj : public CObject
  {
private:
   string            m_file_name;      // Path + file name + extension
   string            m_description;    // File text description
public:
//--- Set (1) file name, (2) file description
   void              FileName(const string name)                  { this.m_file_name=name;      }
   void              Description(const string descr)              { this.m_description=descr;   }
//--- Return (1) file name, (2) file description
   string            FileName(void)                         const { return this.m_file_name;    }
   string            Description(void)                      const { return this.m_description;  }
//--- Compare CResObj objects by properties (to search for equal resource objects)
   bool              IsEqual(const CResObj* compared_obj)   const { return this.Compare(compared_obj,0)==0; }
//--- Compare CResObj objects by all properties (for sorting)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- コンストラクタ
                     CResObj(void){;}
  };
//+------------------------------------------------------------------+
//| Compare CResObj objects                                          |
//+------------------------------------------------------------------+
int CResObj::Compare(const CObject *node,const int mode=0) const
  {
   const CResObj *obj_compared=node;
   if(mode==0)
      return(this.m_file_name>obj_compared.m_file_name ? 1 : this.m_file_name<obj_compared.m_file_name ? -1 : 0);
   else
      return(this.m_description>obj_compared.m_description ? 1 : this.m_description<obj_compared.m_description ? -1 : 0);
  }
//+------------------------------------------------------------------+


必要なファイルをすぐにインクルードします。標準ライブラリのCObjectクラスインスタンスへのポインタの動的配列のクラスとその子孫およびCFileGenライブラリファイルを生成するクラスです。

記述子オブジェクトをCArrayObjリストに保存できるようにするには、このオブジェクトをCObject標準ライブラリの基本クラス子孫にする必要があります。
すべてのクラスメンバ変数とメソッドは、コードコメントで説明されています。それらの目的の詳細な分析について説明する意味はありません。
Compare()仮想メソッドは、デフォルトでファイル名で2つの記述子オブジェクトのフィールドを比較することに注意してください。2つのオブジェクトの比較されたフィールドが等しい場合、メソッドはゼロを返します。オブジェクトをファイル記述で比較する必要がある場合は、 modeを1に設定する必要があります。
オブジェクト等価フラグを返すIsEqual()メソッドは、ファイル名のみでオブジェクトを比較します(1つのフォルダーに同じ名前のファイルが2つあることはできないため)。 デフォルトでは、このメソッドはCompare()メソッドの操作結果を「mode」(0)で返します。これはファイル名による比較に対応しています。

プログラムリソースファイルを記述する記述子オブジェクトのコレクションクラスを実装しましょう。

//+------------------------------------------------------------------+
//| Collection class of resource files descriptor objects            |
//+------------------------------------------------------------------+
class CResourceCollection
  {
private:
//--- List of pointers to descriptor objects
   CArrayObj         m_list_dscr_obj;
//--- Create a file descriptor object and add it to the list
   bool              CreateFileDescrObj(const string file_name,const string descript);
//--- Add a new object to the list of descriptor objects
   bool              AddToList(CResObj* element);
public:
//--- Create a file and add its description to the list
   bool              CreateFile(const ENUM_FILE_TYPE file_type,const string file_name,const string descript,const uchar &file_data_array[]);
//--- Return the (1) list of pointers to descriptor objects, (2) index of the file descriptor object by description
   CArrayObj        *GetList(void)  { return &this.m_list_dscr_obj;  }
   int               GetIndexResObjByDescription(const string file_description);
//--- コンストラクタ
                     CResourceCollection(void);
  };
//+------------------------------------------------------------------+


各メソッドの目的もリストで設定されているため、クラスメソッドに進みましょう。

コンストラクタをクラス本体の外側で実装します。

//+------------------------------------------------------------------+
//| コンストラクタ                                                     |
//+------------------------------------------------------------------+
CResourceCollection::CResourceCollection()
  {
   this.m_list_dscr_obj.Clear();
   this.m_list_dscr_obj.Sort();
  }
//+------------------------------------------------------------------+


ここで、記述子オブジェクトのリストがクリアされファイル名による並び替えのフラグがリストに設定されています(デフォルトは0)。

以下は、ファイルを作成し、コレクションリストに記述子オブジェクトを追加するメソッドです。

//+------------------------------------------------------------------+
//| Create a file and add its descriptor object to the list          |
//+------------------------------------------------------------------+
bool CResourceCollection::CreateFile(const ENUM_FILE_TYPE file_type,const string file_name,const string descript,const uchar &file_data_array[])
  {
   if(!CFileGen::Create(file_type,file_name,file_data_array))
     {
      if(!::FileIsExist(CFileGen::Name()))
         return false;
     }
   return this.CreateFileDescrObj(file_type,CFileGen::Name(),descript);
  }
//+------------------------------------------------------------------+


このメソッドは、作成されたファイルの種類(音声またはイメージ)、ファイル名ファイルの記述、ファイルを構成するファイルデータのバイナリ配列へのリンクを受け取ります。

CFileGenクラスのCreate()メソッドを使用してファイルを作成できずファイルが実際に存在しない場合(既に存在する可能性があり、そのため再作成できない場合)、 falseを返します
ファイルが存在せず、作成されたばかりの場合は、 記述子オブジェクトを生成し、メソッドからファイル記述子オブジェクトのコレクションリストに追加するメソッドの操作結果を返します

以下は、ファイル記述オブジェクトを作成し、コレクションリストに追加するメソッドです。

//+------------------------------------------------------------------+
//| Create a file descriptor object and add it to the list           |
//+------------------------------------------------------------------+
bool CResourceCollection::CreateFileDescrObj(const string file_name,const string descript)
  {
   CResObj *res_dscr=new CResObj();
   if(res_dscr==NULL)
     {
      Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_RES_LINK));
      return false;
     }
   res_dscr.FileName(file_name);
   res_dscr.Description(descript);
   if(!this.AddToList(res_dscr))
     {
      delete res_dscr;
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+


メソッドはファイル名ファイルの記述を受け取ります。
新しいファイル記述子オブジェクトを作成しますオブジェクトが作成できなかった場合は適切なメッセージを操作ログに表示してfalseを返します
次に、ファイルの記述だけでなく、 新しく作成された記述子オブジェクトのファイル名を設定して、コレクションリストに追加します。オブジェクトが追加できなかった場合、メモリリークを避けるためにオブジェクトを破棄する必要があります。オブジェクトを削除してfalseを返します
その他の場合、trueを返します。オブジェクトは正常に作成されてコレクションに追加されています。

以下は、新しい記述オブジェクトをコレクションリストに追加するメソッドです。

//+------------------------------------------------------------------+
//| Add a new object to the list of file descriptor objects          |
//+------------------------------------------------------------------+
bool CResourceCollection::AddToList(CResObj *element)
  {
   this.m_list_dscr_obj.Sort();
   if(this.m_list_dscr_obj.Search(element)>WRONG_VALUE)
      return false;
   return this.m_list_dscr_obj.Add(element);
  }
//+------------------------------------------------------------------+


メソッドは記述オブジェクトを受け取って、コレクションリストにファイル名による並び替えフラグが設定されます同じ名前のオブジェクトがリストに既に存在する場合、falseを返します
それ以外の場合、オブジェクトを追加するためのメソッドの操作結果をリストに 返します

以下は、リスト内の記述オブジェクトをファイル記述で返すメソッドです。

//+----------------------------------------------------------------------+
//| Return the index of the file descriptor object by a file description |
//+----------------------------------------------------------------------+
int CResourceCollection::GetIndexResObjByDescription(const string file_description)
  {
   CResObj *obj=new CResObj();
   if(obj==NULL)
      return WRONG_VALUE;
   obj.Description(file_description);
   this.m_list_dscr_obj.Sort(1);
   int index=this.m_list_dscr_obj.Search(obj);
   delete obj;
   return index;
  }
//+------------------------------------------------------------------+


メソッドは、記述オブジェクトを見つけるのに使用されるファイル記述を受け取ります記述子オブジェクトの一時インスタンスを作成し、メソッドに渡されたファイル記述を記述フィールドで設定します
コレクションリストにファイル記述による並び替えフラグを設定し(1)、記述フィールドに必要なテキストが含まれている記述オブジェクトのインデックスを取得します
一時オブジェクトを必ず削除して取得したインデックスを返します(コレクションリストにこの記述オブジェクトがない場合は-1)。

ファイル記述子オブジェクトコレクションのクラスの準備ができました。

次に、CEngineライブラリの基本オブジェクトにいくつかのメソッドを追加します。

\MQL5\Include\DoEasy\Engine.mqhファイルを開いて記述オブジェクトコレクションファイルをインクルードします

//+------------------------------------------------------------------+
//|                                                       Engine.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| ファイルをインクルードする                                                    |
//+------------------------------------------------------------------+
#include "Services\TimerCounter.mqh"
#include "Collections\HistoryCollection.mqh"
#include "Collections\MarketCollection.mqh"
#include "Collections\EventsCollection.mqh"
#include "Collections\AccountsCollection.mqh"
#include "Collections\SymbolsCollection.mqh"
#include "Collections\ResourceCollection.mqh"
//+------------------------------------------------------------------+


アプリケーションリソース(ファイル記述子のコレクション)の新しいコレクションオブジェクトを作成します。

//+------------------------------------------------------------------+
//| ライブラリ基本クラス                                              |
//+------------------------------------------------------------------+
class CEngine : public CObject
  {
private:
   CHistoryCollection   m_history;                       // 過去の注文と取引のコレクション
   CMarketCollection    m_market;                        // 注文と取引のコレクション
   CEventsCollection    m_events;                        // Event collection
   CAccountsCollection  m_accounts;                      // Account collection
   CSymbolsCollection   m_symbols;                       // Symbol collection
   CResourceCollection  m_resource;                      // Resource list
   CArrayObj            m_list_counters;                 // タイマーカウンタのリスト
   int                  m_global_error;                  // Global error code
   bool                 m_first_start;                   // 初期実行フラグ
   bool                 m_is_hedge;                      // ヘッジ勘定フラグ
   bool                 m_is_tester;                     // Flag of working in the tester
   bool                 m_is_market_trade_event;         // 口座取引イベントフラグ
   bool                 m_is_history_trade_event;        // 口座過去の取引イベントフラグ
   bool                 m_is_account_event;              // Account change event flag
   bool                 m_is_symbol_event;               // Symbol change event flag
   ENUM_TRADE_EVENT     m_last_trade_event;              // Last account trading event
   int                  m_last_account_event;            // Last event in the account properties
   int                  m_last_symbol_event;             // Last event in the symbol properties
//--- IDによるカウンタインデックスを返す


そしてプログラムリソースコレクションを操作するための3つの新しいメソッドを追加します。

//--- タイマー
   void                 OnTimer(void);
//--- Set the list of used symbols
   bool                 SetUsedSymbols(const string &array_symbols[])   { return this.m_symbols.SetUsedSymbols(array_symbols);}
   
//--- Create a resource file
   bool                 CreateFile(const ENUM_FILE_TYPE file_type,const string file_name,const string descript,const uchar &file_data_array[])
                          {
                           return this.m_resource.CreateFile(file_type,file_name,descript,file_data_array);
                          }
//--- Return the list of links to resources
   CArrayObj           *GetListResource(void)                                 { return this.m_resource.GetList();                               }
   int                  GetIndexResObjByDescription(const string file_name)   { return this.m_resource.GetIndexResObjByDescription(file_name);  }

//--- Return event (1) milliseconds, (2) reason and (3) source from its 'long' value
   ushort               EventMSC(const long lparam)               const { return this.LongToUshortFromByte(lparam,0);         }
   ushort               EventReason(const long lparam)            const { return this.LongToUshortFromByte(lparam,1);         }
   ushort               EventSource(const long lparam)            const { return this.LongToUshortFromByte(lparam,2);         }
   
//--- コンストラクタ/デストラクタ
                        CEngine();
                       ~CEngine();
  };
//+------------------------------------------------------------------+


メソッドは、記述子オブジェクトのコレクションクラスのメソッドと同じ名前を持ち、このクラスから同じ名前のメソッドを呼び出します。

作成されたクラスをテストするには、バイナリ配列のファイルを含むDataSND.mqhおよびDataIMG.mqhで利用可能なデータに従ってすべてのファイルを作成します。エクスパート操作ログで、バイナリ配列からファイルを作成した結果を表示し、ファイル記述子オブジェクトの結果のコレクションリストの内容を表示します。また、音声の1つを再生して、画面の右下隅に赤と緑のLEDを描いた2つの作成された画像ファイルで構成される画像を表示しましょう。

自動作成されたファイルへのアクセスのテスト

前の記事からのTestDoEasyPart19.mq5 EAを\MQL5\Experts\TestDoEasy\ Part20\ TestDoEasyPart20.mq5として保存して使用しましょう。

ファイルはプログラムの最初の起動時に作成する必要があるため、プログラムリソースを作成するためのクラスはOnInit()で処理する必要があります。取得した結果もそこでテストする必要があります。

OnInit()ハンドラの最後に次のコードブロックを追加します。

//--- Set CTrade trading class parameters
#ifdef __MQL5__
   trade.SetDeviationInPoints(slippage);
   trade.SetExpertMagicNumber(magic_number);
   trade.SetTypeFillingBySymbol(Symbol());
   trade.SetMarginMode();
   trade.LogLevel(LOG_LEVEL_NO);
#endif 
//--- Create and check the resource files
   Print("\n",TextByLanguage("--- Проверка успешности создания файлов ---","--- Verifying files were created ---"));
   string dscr=TextByLanguage("Проверка существования файла: ","Checking existence of file: ");
   
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_01",TextByLanguage("Звук упавшей монетки 1","Sound of falling coin 1"),sound_array_coin_01);
   if(CFileGen::IsExist(FILE_TYPE_WAV,"sound_array_coin_01"))
      Print(dscr+CFileGen::Name(),": OK");
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_02",TextByLanguage("Звук упавших монеток","Sound fallen coins"),sound_array_coin_02);
   if(CFileGen::IsExist(FILE_TYPE_WAV,"sound_array_coin_02"))
      Print(dscr+CFileGen::Name(),": OK");
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_03",TextByLanguage("Звук монеток","Sound of coins"),sound_array_coin_03);
   if(CFileGen::IsExist(FILE_TYPE_WAV,"sound_array_coin_03"))
      Print(dscr+CFileGen::Name(),": OK");
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_04",TextByLanguage("Звук упавшей монетки 2","Sound of falling coin 2"),sound_array_coin_04);
   if(CFileGen::IsExist(FILE_TYPE_WAV,"sound_array_coin_04"))
      Print(dscr+CFileGen::Name(),": OK");
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_01",TextByLanguage("Звук щелчка по кнопке 1","Click on button sound 1"),sound_array_click_01);
   if(CFileGen::IsExist(FILE_TYPE_WAV,"sound_array_click_01"))
      Print(dscr+CFileGen::Name(),": OK");
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_02",TextByLanguage("Звук щелчка по кнопке 2","Click on button sound 1"),sound_array_click_02);
   if(CFileGen::IsExist(FILE_TYPE_WAV,"sound_array_click_02"))
      Print(dscr+CFileGen::Name(),": OK");
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_03",TextByLanguage("Звук щелчка по кнопке 3","Click on button sound 1"),sound_array_click_03);
   if(CFileGen::IsExist(FILE_TYPE_WAV,"sound_array_click_03"))
      Print(dscr+CFileGen::Name(),": OK");
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_cash_machine_01",TextByLanguage("Звук кассового аппарата","Sound of cash machine"),sound_array_cash_machine_01);
   if(CFileGen::IsExist(FILE_TYPE_WAV,"sound_array_cash_machine_01"))
      Print(dscr+CFileGen::Name(),": OK");

   engine.CreateFile(FILE_TYPE_BMP,"img_array_spot_green",TextByLanguage("Изображение \"Зелёный светодиод\"","Image \"Green Spot lamp\""),img_array_spot_green);
   if(CFileGen::IsExist(FILE_TYPE_BMP,"img_array_spot_green"))
      Print(dscr+CFileGen::Name(),": OK");
   engine.CreateFile(FILE_TYPE_BMP,"img_array_spot_red",TextByLanguage("Изображение \"Красный светодиод\"","Image \"Red Spot lamp\""),img_array_spot_red);
   if(CFileGen::IsExist(FILE_TYPE_BMP,"img_array_spot_red"))
      Print(dscr+CFileGen::Name(),": OK");

//--- Check the file description list
   Print("\n",TextByLanguage("--- Проверка списка описания файлов ---","--- Checking file description list ---"));
   CArrayObj* list_res=engine.GetListResource();
   if(list_res!=NULL)
     {
      //--- Let's see the entire list of file descriptions
      for(int i=0;i<list_res.Total();i++)
        {
         CResObj *res=list_res.At(i);
         if(res==NULL)
            continue;
         //--- Display the paths to the files and the file description in the journal
         string type=(StringFind(res.FileName(),"\\Sounds\\")>0 ? TextByLanguage("Звук ","Sound ") : TextByLanguage("Изображение ","Image "));
         Print(type,string(i+1),": ",TextByLanguage("Имя файла :","File name: "),res.FileName()," (",res.Description(),")");
         
         //--- If the current description corresponds to the falling coin sound 1, play the appropriate sound
         if(res.Description()==TextByLanguage("Звук упавшей монетки 1","Sound of falling coin 1"))
           {
            CMessage::PlaySound(res.FileName());
           }
        }
      //--- Create the image of the red-green LED
      //--- Get the indices of red and green LEDs image descriptions
      int index_r=engine.GetIndexResObjByDescription(TextByLanguage("Изображение \"Красный светодиод\"","Image \"Red Spot lamp\""));
      int index_g=engine.GetIndexResObjByDescription(TextByLanguage("Изображение \"Зелёный светодиод\"","Image \"Green Spot lamp\""));
      if(index_g>WRONG_VALUE && index_r>WRONG_VALUE)
        {
         //--- Get two objects with files description from the list
         CResObj *res_g=list_res.At(index_g);
         CResObj *res_r=list_res.At(index_r);
         if(res_g==NULL || res_r==NULL)
           {
            Print(TextByLanguage("Не удалось получить данные с описанием файла изображения","Failed to get image file description data"));
            return(INIT_SUCCEEDED);
           }
         //--- Create a button based on image files
         long chart_ID=ChartID();
         string name=prefix+"RedGreenSpot";
         if(ObjectCreate(chart_ID,name,OBJ_BITMAP_LABEL,0,0,0))
           {
            ObjectSetString(chart_ID,name,OBJPROP_BMPFILE,0,"\\Files\\"+res_g.FileName());   // Изображение для нажатой кнопки
            ObjectSetString(chart_ID,name,OBJPROP_BMPFILE,1,"\\Files\\"+res_r.FileName());   // Released button image
            ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,CORNER_RIGHT_LOWER);
            ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,ANCHOR_RIGHT_LOWER);
            ObjectSetInteger(chart_ID,name,OBJPROP_STATE,true);
            ObjectSetInteger(chart_ID,name,OBJPROP_XSIZE,16); 
            ObjectSetInteger(chart_ID,name,OBJPROP_YSIZE,16);
            ObjectSetInteger(chart_ID,name,OBJPROP_XOFFSET,0); 
            ObjectSetInteger(chart_ID,name,OBJPROP_YOFFSET,0);
            ObjectSetInteger(chart_ID,name,OBJPROP_BACK,false);
            ObjectSetInteger(chart_ID,name,OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS);
            ChartRedraw(chart_ID);
           }
        }
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+


ここでは、ライブラリのソースコードのバイナリ配列にあるデータからファイルを作成しました。各ファイルを作成した後、その存在を確認し、結果を操作ログに表示します。すべてのファイルとその記述子を作成したら、ファイルの作成時にコレクションに追加されたすべてのファイル記述子の完全なリストを確認します。

コードには、すべてのアクションが記載されています。これらは自分自身で分析してください。

EAをコンパイルした後、ファイル作成結果を操作ログに表示し、コインの落下音を再生し、画面の右下隅に2つの画像で構成されるLED画像を表示します。LEDをクリックして画像を切り替えることができます。実際、これは2つの状態(オン/オフ)を持つボタンです。



ご覧のとおり、すべてが想定どおりに機能します。正常なファイル生成に関するメッセージが操作ログに表示され、クリックするとLEDの色が変わり、ターミナルデータフォルダを開いて([File]-> [Open Data Folder])MQL5\Files\DoEasy\Resource\に入ると、 新しく作成されたすべてのファイルを含むImagesサブフォルダとSoundsサブフォルダを見ることができます。

次の段階

次の記事からは、取引クラスとそれに関連する新しいライブラリセクションを開きます。

現在のバージョンのライブラリのすべてのファイルは、テスト用EAファイルと一緒に以下に添付されているので、テストするにはダウンロードしてください。
質問、コメント、提案はコメント欄にお願いします。

目次に戻る

シリーズのこれまでの記事:

第1部: 概念、データ管理
第2部: 過去の注文と取引のコレクション
第3部: 注文と取引のコレクション、検索と並び替え
第4部: 取引イベント概念
第5部: 取引イベントのクラスとコレクション取引イベントのプログラムへの送信
第6部: ネッティング勘定イベント
第7部: StopLimit注文発動イベント、注文およびポジション変更イベントの機能の準備
第8部: 注文とポジションの変更イベント
第9部: MQL4との互換性 - データの準備
第10部: MQL4との互換性 - ポジションオープンイベントと指値注文発動イベント
第11部: MQL4との互換性 - ポジション決済イベント
第12部: 口座オブジェクトクラスと口座オブジェクトコレクション
第13部: 口座オブジェクトイベント第14部: 銘柄オブジェクト
第15部: 銘柄オブジェクトコレクション
第16部: 銘柄コレクションイベント
第17部: ライブラリオブジェクトの相互作用
第18部:口座と他のライブラリオブジェクトの相互作用
第19部:ライブラリメッセージの クラス