ライブラリ: DLLなしでのファイルマッピング - ページ 11 1...456789101112 新しいコメント Алексей Барбашин 2017.10.23 22:17 #101 o_o:レコードを閉じるのではなく、ファイルを閉じて削除 するのだ。だから そのため、あなたはもう存在しないものを開こうとしているのです。ライブラリのコードを見てみると、ファイルが削除されるのは、CMemMapFileクラスのClose()関数が直接呼ばれたときだけでなく、このクラスのオブジェクトへのポインタが削除されたときでもあることがわかりました。私は少し困惑しています。ファイルの書き込みと読み込みが異なる呼び出しコンテキスト(スコープ)で使用されている場合、クラスオブジェクトを作成する動的メソッドは使用できないことがわかりました。例えば、ターミナルの1つのチャートがファイルにデータを書き込み、2番目のチャートがデータを読み込んでこのファイルを削除する。ファイルが強制的に削除されないように、オブジェクト変数は常にグローバル・レベルに保持されるべきであることが判明した。また、読み込んだデータのサイズを指定しなくても可能かどうかも不明である。つまり、データを書き込むときにはそのサイズを知っているが、別のチャートで読み込むときには、たとえば文字列の値のように、事前にデータのサイズを知らない場合がある。おそらく、私が何かを誤解しているか、ライブラリに微調整すべき点があるのだろう。失礼しました。ポインターを使わずに、つまりdeleteを使わずに再確認してみました。この場合、(関数から)スコープを離れるとき、クラスオブジェクトのローカル変数は、明示的にデストラクタを呼び出すことなく破棄されます。受信側で受信したデータのサイズに疑問が残る。 Алексей Барбашин 2017.10.24 10:03 #102 fxsaber:ライブラリを提供してくれた作者に感謝する!あらゆるデータを転送するための関数を作った。以下のスクリプトは、目盛りの例でその働きを示している。結果スーパー!作者さんのコードから類推して、私自身のためにライブラリの使い方を 簡略化しました。 fxsaber 2017.11.30 14:20 #103 MT4の価格移動の例 取引、自動取引システム、取引戦略のテストに関するフォーラム メタトレーダー4のNamedPipes fxsaber, 2017.11.30 14:18 取引所データ.mqh#include <MemMapLib.mqh> #include <TypeToBytes.mqh> template <typename T> class EXCHANGE_DATA { private: CMemMapFile* FileMemory; public: // 指定された長さのメモリをデータ用に確保する。 EXCHANGE_DATA( const int Amount, const bool ModeCreate = false, string FileName = "Local\\test" ) { // FileName += _Symbol; this.FileMemory = new CMemMapFile; if (this.FileMemory.Open(FileName, sizeof(T) * Amount + sizeof(int) + HEAD_MEM, ModeCreate ? modeCreate : modeOpen) != 0) { Alert("FileMemory.Open - ERROR!"); delete &this; } } ~EXCHANGE_DATA( void ) { this.FileMemory.Close(); delete this.FileMemory; } // データをメモリに書き込む void DataSave( const T &Data[], const bool FromBegin = true ) const { const int Size = ::ArraySize(Data) * sizeof(T); uchar Bytes[]; _ArrayCopy(Bytes, _R(Size).Bytes); // 数量を記録 _ArrayCopy(Bytes, _R(Data).Bytes, sizeof(int)); // データを記録 if (FromBegin) this.FileMemory.Seek(0, SEEK_SET); this.FileMemory.Write(Bytes, ::ArraySize(Bytes)); // すべてをメモリにダンプ return; } // メモリからデータを読み込む int DataLoad( T &Data[], const bool FromBegin = true ) const { if (FromBegin) this.FileMemory.Seek(0, SEEK_SET); uchar Bytes[]; this.FileMemory.Read(Bytes, sizeof(int)); // メモリからデータ量を読み出す this.FileMemory.Read(Bytes, _R(Bytes)[0]); // データそのものを取得 _ArrayCopy(Data, Bytes); // データを配列にダンプ return(::ArraySize(Data)); } };プライスギバー.mq4#property strict #include "Exchange_Data.mqh" #define AMOUNT 100 EXCHANGE_DATA<MqlTick> ExchangeTicks(AMOUNT, true); const bool Init = EventSetMillisecondTimer(100); void OnTimer( void ) { static MqlTick Ticks[1]; if (SymbolInfoTick(_Symbol, Ticks[0])) ExchangeTicks.DataSave(Ticks); }PriceTaker.mq4#property strict #include "Exchange_Data.mqh" #define AMOUNT 100 EXCHANGE_DATA<MqlTick> ExchangeTicks(AMOUNT); const bool Init = EventSetMillisecondTimer(100); #define TOSTRING(A) (#A + " = " + (string)(A) + " ") void OnTimer( void ) { static MqlTick PrevTick = {0}; MqlTick Ticks[]; if ((ExchangeTicks.DataLoad(Ticks) > 0) && ((Ticks[0].bid != PrevTick.bid) || (Ticks[0].ask != PrevTick.ask))) { Print(TOSTRING(Ticks[0].time) + TOSTRING(Ticks[0].bid) + TOSTRING(Ticks[0].ask)); PrevTick = Ticks[0]; } }PriceGiver.ex4と PriceTaker.ex4を 実行します。実行結果2017.11.30 15:13:55.101 Expert PriceGiver EURUSD,M1: removed 2017.11.30 15:13:55.091 PriceGiver EURUSD,M1: uninit reason 1 2017.11.30 15:13:51.006 Expert PriceTaker GBPAUD,M1: removed 2017.11.30 15:13:50.996 PriceTaker GBPAUD,M1: uninit reason 1 2017.11.30 15:13:49.168 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:41 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 2017.11.30 15:13:48.838 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:41 Ticks[0].bid = 1.18484 Ticks[0].ask = 1.18489 2017.11.30 15:13:48.186 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:40 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 2017.11.30 15:13:47.751 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:40 Ticks[0].bid = 1.18484 Ticks[0].ask = 1.18488 2017.11.30 15:13:42.178 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:34 Ticks[0].bid = 1.18485 Ticks[0].ask = 1.18489 2017.11.30 15:13:41.633 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:34 Ticks[0].bid = 1.18484 Ticks[0].ask = 1.18488 2017.11.30 15:13:37.588 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:30 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 2017.11.30 15:13:36.175 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:28 Ticks[0].bid = 1.18481 Ticks[0].ask = 1.18485 2017.11.30 15:13:30.717 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:23 Ticks[0].bid = 1.18482 Ticks[0].ask = 1.18486 2017.11.30 15:13:29.514 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:22 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 2017.11.30 15:13:27.324 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:19 Ticks[0].bid = 1.1848 Ticks[0].ask = 1.18484 2017.11.30 15:13:26.994 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:19 Ticks[0].bid = 1.18482 Ticks[0].ask = 1.18486 2017.11.30 15:13:26.012 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:18 Ticks[0].bid = 1.18481 Ticks[0].ask = 1.18485 2017.11.30 15:13:25.584 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:18 Ticks[0].bid = 1.18482 Ticks[0].ask = 1.18486 2017.11.30 15:13:25.254 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:16 Ticks[0].bid = 1.18481 Ticks[0].ask = 1.18485 2017.11.30 15:13:25.147 PriceTaker GBPAUD,M1: initialized 2017.11.30 15:13:24.049 Expert Sparring\PriceTaker GBPAUD,M1: loaded successfully 2017.11.30 15:13:21.157 PriceGiver EURUSD,M1: initialized 2017.11.30 15:13:19.617 Expert Sparring\PriceGiver EURUSD,M1: loaded successfully Alexey Navoykov 2018.06.01 07:01 #104 このライブラリでは、CMemMapFile::Openメソッドに小さなエラーがあります。 これはファイルハンドル(HANDLE64型)を返すべきですが、代わりに0またはエラーコードを 返します。さらに、CMemMapApi::WriteとCMemMapApi::Readメソッドでは、なぜかデータが二重に再コピーされ(バイトがループされる!)、さらに、指定された部分のみが必要であるにもかかわらず、ファイル全体が上書き/読み込まれます。一般的に、私はそれらを正常に見えるようにし、不必要なものはコメントアウトされている://------------------------------------------------------------------ Write int CMemMapApi::Write(HANDLE64 hmem, const uchar &buf[], DWORD pos, int sz, DWORD &err) // 指定されたバイト数をメモリに書き込む { if (hmem==NULL) return(-1); PBYTE64 view=ViewFile(hmem, err); if (view==0 || err!=0) return(-1); // 開いていない場合 DWORD size=GetSize(hmem, err); if (pos+sz>size) { UnViewFile(view); return(-2); }; // サイズが小さければ終了 /* uchar src[]; ArrayResize(src, size); memcpyX(src, view, size); // バイトバッファを取得 for(int i=0;i<sz; i++) src[pos+i+HEAD_MEM]=buf[i]; // メモリへの書き込み memcpyX(view, src, size); // コピーバック */ memcpyX(view+HEAD_MEM+pos, buf, sz); UnViewFile(view); // ビューを閉じる return(0); // OKが返された。 } //------------------------------------------------------------------ Read int CMemMapApi::Read(HANDLE64 hmem, uchar &buf[], DWORD pos, int sz, DWORD &err) // 指定されたバイト数をメモリから読み込む { if (hmem==NULL) return(-1); PBYTE64 view=ViewFile(hmem, err); if (view==0 || err!=0) return(-1); // 開いていない場合 DWORD size=GetSize(hmem, err); // サイズを取得 /* uchar src[]; ArrayResize(src, size); memcpyX(src, view, size); // バイトバッファを取った ArrayResize(buf, sz); int i=0; for(i=0; i<sz && pos+i<size; i++) buf[i]=src[pos+i+HEAD_MEM]; // バイトを読み込む */ sz= fmin(sz, size-pos); ArrayResize(buf, sz); memcpyX(buf, view+HEAD_MEM+pos, sz); UnViewFile(view); // ビューを閉じる return sz; // コピーされたバイト数 } 最初の関数をコンパイルするためには、memcpyXと memcpy 関数で配列にconstを 設定する必要がある。 pushdib 2018.06.04 20:06 #105 dwMaximumSizeHighに0が渡されるため、大きなサイズをコピーするとエラーが発生する。 if (mode==modeCreate) hmem=CreateFileMappingWX(INVALID_HANDLE_VALUE64, NULL, PAGE_READWRITE, 0, size + HEAD_MEM, path); // メモリ・オブジェクトを作成する このように修正しました: if (mode==modeCreate) hmem=CreateFileMappingWX(INVALID_HANDLE_VALUE64, NULL, PAGE_READWRITE, size + HEAD_MEM, size + HEAD_MEM, path); // メモリ・オブジェクトを作成する このサイズ(6MB)は問題なく転送される: void OnStart() { int bars = Bars(_Symbol, _Period); MqlRates rates[]; ArraySetAsSeries(rates, true); CopyRates(NULL, 0, 0, bars, rates); int size = ArraySize(rates) * sizeof(MqlRates); uchar data[]; _ArrayCopy(data, rates); CMemMapFile *hmem = new CMemMapFile(); hmem.Open("test", size, modeCreate); hmem.Write(data, size); hmem.Close(); delete hmem; Print(size); } TheXpert 2018.06.04 20:27 #106 pushdib:このように修正した:8バイトサイズの上位4バイトを適切に渡す。 pushdib 2018.06.04 20:52 #107 さて、これでC#プログラムにすべてのレイトが揃い、LINQを使って必要なものをすべて分析できるようになった。 しかし、ターミナルとアプリケーション間のコマンドのメカニズムをどのように整理するかという問題がある。 ターミナルから:新しいロウソク、新しいレイト、ファイルの取得 アプリケーションから:計算が完了し、結果を取る(チャートに描画し、取引を開く)。 どなたかこのようなターミナルとコード間の相互作用の実装の経験をお持ちの方はいらっしゃいませんか? Dmitriy Skub 2018.06.04 21:24 #108 pushdib:さて、これでC#プログラムにすべてのレイトが揃い、LINQを使ってすべてを完璧に分析できるようになった。 しかし、ターミナルとアプリケーション間のコマンドのメカニズムをどのように整理するかという問題がある。 ターミナルから:新しいキャンドル、新しいレート、ファイルの取得アプリケーションから:計算が完了し、結果を取る(チャートに描画し、取引を開く)。このようなターミナルとコード間の相互作用の実装を経験したことがある人はいますか? 私はすべてpipで行いました。 BillionerClub 2019.02.05 18:20 #109 これは本当に素晴らしい!-)).同時にバイナリファイルの 扱い方も学ばなければならなかったが、その価値はあった。 pivomoe 2019.06.20 15:23 #110 このような場合、どうすればよいでしょうか。 1.メモリ上に100バイトの新規ファイルを開いた。 2.100バイトを書き込んだ。 3.別のExpert Advisorで100バイトを読み込んだ。すべて正常です。 4.同じファイルに50バイトや200バイトを書き込むには? 1...456789101112 新しいコメント 取引の機会を逃しています。 無料取引アプリ 8千を超えるシグナルをコピー 金融ニュースで金融マーケットを探索 新規登録 ログイン スペースを含まないラテン文字 このメールにパスワードが送信されます エラーが発生しました Googleでログイン WebサイトポリシーおよびMQL5.COM利用規約に同意します。 新規登録 MQL5.com WebサイトへのログインにCookieの使用を許可します。 ログインするには、ブラウザで必要な設定を有効にしてください。 ログイン/パスワードをお忘れですか? Googleでログイン
レコードを閉じるのではなく、ファイルを閉じて削除 するのだ。
だから
そのため、あなたはもう存在しないものを開こうとしているのです。ライブラリのコードを見てみると、ファイルが削除されるのは、CMemMapFileクラスのClose()関数が直接呼ばれたときだけでなく、このクラスのオブジェクトへのポインタが削除されたときでもあることがわかりました。私は少し困惑しています。ファイルの書き込みと読み込みが異なる呼び出しコンテキスト(スコープ)で使用されている場合、クラスオブジェクトを作成する動的メソッドは使用できないことがわかりました。例えば、ターミナルの1つのチャートがファイルにデータを書き込み、2番目のチャートがデータを読み込んでこのファイルを削除する。ファイルが強制的に削除されないように、オブジェクト変数は常にグローバル・レベルに保持されるべきであることが判明した。また、読み込んだデータのサイズを指定しなくても可能かどうかも不明である。つまり、データを書き込むときにはそのサイズを知っているが、別のチャートで読み込むときには、たとえば文字列の値のように、事前にデータのサイズを知らない場合がある。おそらく、私が何かを誤解しているか、ライブラリに微調整すべき点があるのだろう。
失礼しました。ポインターを使わずに、つまりdeleteを使わずに再確認してみました。この場合、(関数から)スコープを離れるとき、クラスオブジェクトのローカル変数は、明示的にデストラクタを呼び出すことなく破棄されます。
受信側で受信したデータのサイズに疑問が残る。
ライブラリを提供してくれた作者に感謝する!
あらゆるデータを転送するための関数を作った。以下のスクリプトは、目盛りの例でその働きを示している。
結果
スーパー!作者さんのコードから類推して、私自身のためにライブラリの使い方を 簡略化しました。
取引、自動取引システム、取引戦略のテストに関するフォーラム
メタトレーダー4のNamedPipes
fxsaber, 2017.11.30 14:18
取引所データ.mqh
プライスギバー.mq4
PriceTaker.mq4
PriceGiver.ex4と PriceTaker.ex4を 実行します。
実行結果
このライブラリでは、CMemMapFile::Openメソッドに小さなエラーがあります。 これはファイルハンドル(HANDLE64型)を返すべきですが、代わりに0またはエラーコードを 返します。
さらに、CMemMapApi::WriteとCMemMapApi::Readメソッドでは、なぜかデータが二重に再コピーされ(バイトがループされる!)、さらに、指定された部分のみが必要であるにもかかわらず、ファイル全体が上書き/読み込まれます。
一般的に、私はそれらを正常に見えるようにし、不必要なものはコメントアウトされている:
最初の関数をコンパイルするためには、memcpyXと memcpy 関数で配列にconstを 設定する必要がある。dwMaximumSizeHighに0が渡されるため、大きなサイズをコピーするとエラーが発生する。
このように修正しました:
このサイズ(6MB)は問題なく転送される:
このように修正した:
8バイトサイズの上位4バイトを適切に渡す。
さて、これでC#プログラムにすべてのレイトが揃い、LINQを使って必要なものをすべて分析できるようになった。
しかし、ターミナルとアプリケーション間のコマンドのメカニズムをどのように整理するかという問題がある。
ターミナルから:新しいロウソク、新しいレイト、ファイルの取得
アプリケーションから:計算が完了し、結果を取る(チャートに描画し、取引を開く)。
どなたかこのようなターミナルとコード間の相互作用の実装の経験をお持ちの方はいらっしゃいませんか?
さて、これでC#プログラムにすべてのレイトが揃い、LINQを使ってすべてを完璧に分析できるようになった。
しかし、ターミナルとアプリケーション間のコマンドのメカニズムをどのように整理するかという問題がある。
ターミナルから:新しいキャンドル、新しいレート、ファイルの取得
アプリケーションから:計算が完了し、結果を取る(チャートに描画し、取引を開く)。
このようなターミナルとコード間の相互作用の実装を経験したことがある人はいますか?
このような場合、どうすればよいでしょうか。
1.メモリ上に100バイトの新規ファイルを開いた。
2.100バイトを書き込んだ。
3.別のExpert Advisorで100バイトを読み込んだ。すべて正常です。
4.同じファイルに50バイトや200バイトを書き込むには?