🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

MQL4

MQL4とは、MT4(MetaTrader4)で用いられるプログラム言語です。MT4は無料で使えるチャートソフトあり、MQL4を使うことで分析ツールのオリジナルスクリプトの作成ができます。

DLL

DLL(Dynamic Link Library)とは、他のモジュールからも使用する事が出来る、関数とデータが格納されているモジュールのことです。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

2798閲覧

【MQL4】MQL4から呼び出しているdllモジュール内で任意のフォルダにファイル書き込みを行いたい

OXamarin

総合スコア59

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

MQL4

MQL4とは、MT4(MetaTrader4)で用いられるプログラム言語です。MT4は無料で使えるチャートソフトあり、MQL4を使うことで分析ツールのオリジナルスクリプトの作成ができます。

DLL

DLL(Dynamic Link Library)とは、他のモジュールからも使用する事が出来る、関数とデータが格納されているモジュールのことです。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2021/01/26 13:21

##困っている事
MQL4から呼び出しているdllモジュール内で任意のフォルダにファイル書き込みをしようとすると、
MT4のログに「0xE0434352」と出力され強制的に実行中止されてしまう。

##実現したい事
インジケーター実行時に最大で5分毎に20万文字(日本語を含む)をファイルに書き込みをしたいです。(都度情報が更新されるので、それを保持してチャート上に描画していきたい)

##やってみたこと
画面に表示する情報量が非常に多く処理が煩雑なので、
C#でモジュールを作成し、そのモジュールをMQL4 に読み込ませて処理結果をstringで受け取ろうと考えていました。

この実装自体は出来たのですが、MQL4のstring型で正しく文字が取得できていない事に気付きました。
仕様を確認してみると、255文字までしか受け取れないらしく、20万文字を取得することは諦め、C#上で20万文字分をファイル書き込みする事にしました。

###問題点1
しかしすぐに問題に直面します。
C#のライブラリ上でファイル書き込みをしようと(例えば、filestreamのインスタンス生成をするだけ、File.WriteTextAllの実行時など)するとMT4のログに「0xE0434352」と出力されてしまいます。理由は全くの不明です。
これが解決できれば一番楽です。

###問題点2
諦めきれなかったので色々と考え、Kernel32.dll であればMQL4内で扱える事を思い出しました。
Kernel32.dll のCreateFile,WriteFileメソッドを使用すればファイルに書き込めるはず…!と思いましたが、WriteFileメソッドはbyte[]型でしか書き込めない為、それをMQL4側で復元しなければならずその方法がないと思い諦めました。

###問題点3
更に思考を変え、C#内でPrcessStartを行い、別のexeを実行しexeからファイル書き込みをすればよいと考えました。
実際、「notepad」を実行させ、MQL4からメモ帳を開ける事は確認できました。
書き込み先のファイルパスと書き込むテキストの2引数を受け取るコンソールアプリケーションを作成し、それを呼び出すようにしましたが、MT4のログに「0xE0434352」と出力されてしまいます。

ProcessStartのワーキングディレクトリへのパス設定をしてもうまく行かなかったので、System32フォルダへ配置し、コマンドプロンプトから実行できることは確認しています。また、ProcessStartの呼び出しを行う1行を抜いた上で正常に動作することは確認していますが、やはりうまくいきませんでした。

どのようにすれば、MQL4から呼び出しているdllモジュール内で任意のフォルダにファイル書き込みをすることができるのでしょうか。

####補足
書き込み先は、MQLのFilesフォルダ以下です。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2021/01/26 17:32

MT4もMT5もファイルサンドボックス外のファイル操作はセキュリティ上の理由でできないようで、故に任意の自由なディレクトリ下にファイルを配置しての操作は不可能なようですが、Windowsの名前付きパイプ(Named Pipe)を使ってデータを別プロセスと送受信する例が見受けられます。 「MT4 NamedPipe」などと検索するといくつかヒットするので、参考にされてみてはいかがでしょうか。
guest

回答1

0

ベストアンサー

C#のDLL内で例外が出ると0xE0434352になるみたいです。
また、MQL4の文字列の255文字までというのは文字列定数の制限です。

ファイル書き込みと文字列受け取りを試しに作成してみました。

C#

1using System; 2using System.IO; 3using System.Runtime.InteropServices; 4using System.Text; 5 6namespace CsMT4Dll 7{ 8 public class Class1 9 { 10 [DllExport] 11 public static int WriteFile(IntPtr pathPtr) 12 { 13 var path = Marshal.PtrToStringUni(pathPtr); 14 15 try 16 { 17 File.WriteAllText(path, DateTimeOffset.Now.ToString("O")); 18 } 19 catch (Exception) 20 { 21 return -1; 22 } 23 24 return 0; 25 } 26 27 [DllExport] 28 public static int GetResult(IntPtr p, int size) 29 { 30 StringBuilder b = new StringBuilder(); 31 for (int i = 0; i < 180000; i++) 32 { 33 b.AppendLine($"処理結果 = {i}"); 34 } 35 36 var bytes = Encoding.UTF8.GetBytes(b.ToString()); 37 if (bytes.Length > size) 38 { 39 return -1; 40 } 41 42 Marshal.Copy(bytes, 0, p, bytes.Length); 43 44 return bytes.Length; 45 } 46 } 47}

MQL4

1#property strict 2 3#import "CsMT4Dll.dll" 4int WriteFile(string); 5int GetResult(uchar& result[], int size); 6#import 7 8void OnStart() 9{ 10 string path = TerminalInfoString(TERMINAL_DATA_PATH) + "\MQL4\Files\cstest.txt"; 11 12 // 書き込みテスト 13 int ret = WriteFile(path); 14 printf("ret = %d", ret); 15 16 // 文字列受け取りテスト 17 uchar result[]; 18 ArrayResize(result, 600000); 19 int len = GetResult(result, 600000); 20 if (len >= 0) 21 { 22 string s = CharArrayToString(result, 0, len, CP_UTF8); 23 printf("len = %d", StringLen(s)); 24 printf("%s", StringSubstr(s, 0, 10)); 25 printf("%s", StringSubstr(s, StringLen(s) - 10, 10)); 26 } 27}

投稿2021/01/26 17:59

mah

総合スコア591

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

OXamarin

2021/01/28 03:40

おお、神よ。本当に、本当にありがとうございます。 ファイルパス生成に、MQL側から渡してきた文字列を置換したりしていたのですが、 そうする為にはマーシャリングか、mahさんのようにIntPtr型で受け取らなければいけなかったのですね。 ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問