質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

MQL4

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

cURL

cURLはHTTP, FTPやTelnetなど複数のプロトコルを用いてデータを転送するライブラリとコマンドラインツールを提供します。

DLL

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

C++

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

Q&A

解決済

1回答

1726閲覧

MQL4プログラムでlibcurlを用いたDLLを正しく実行することができません。

SorasoSukhavati

総合スコア17

Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

MQL4

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

cURL

cURLはHTTP, FTPやTelnetなど複数のプロトコルを用いてデータを転送するライブラリとコマンドラインツールを提供します。

DLL

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

C++

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

0グッド

0クリップ

投稿2019/11/14 15:43

前提・実現したいこと

MQL4からDLLを用いて、LineNotifyのAPIを叩くプログラムを作成しています。
インジケーターからWebRequest関数を用いることが不可能だったので、DLLを使おうと考えました。

Windows10を使用しているので、MinGW(32bit)を導入しg++コンパイラを用いてc++のプログラムをDLL化しようと試みました。LineNotifyのAPIを叩くために、libcurl(32bit)をインストールしました。

C++単体のプログラムではlibcurlの関数を使って、LineNotifyにPOSTリクエストを送ることができました。また、libcurlの関数を使用せずにMQL4からDLLを使うこともできました。(適当な整数値を返すだけの関数を使用)

使用プログラム
・NoticeTest.mq4(dllを呼び出すプログラム)
・LineNotification.cpp(dll化するプログラム)
・libLineNotification.dll

ここまでが前提となります。

発生している問題・エラーメッセージ

libcurlの関数を使ってDLL化を行い、mq4から呼び出そうとすると以下のエラーがエキスパートに出力されます。

2019.11.15 00:12:01.898 NoticeTest USDJPY,M5: not initialized 2019.11.15 00:12:01.897 Access violation read to 0x00409160

該当のソースコード

NoticeTest.mq4

MQL4

1#property copyright "meta" 2#property link "https://" 3#property version "1.00" 4 5#import "libLineNotification.dll" 6 int notifyLineAPI(); 7#import 8 9int OnInit() 10{ 11 int canRead = notifyLineAPI(); 12 Comment( canRead ); 13 14 return(INIT_SUCCEEDED); 15} 16 17int OnCalculate(const int rates_total, 18 const int prev_calculated, 19 const datetime &time[], 20 const double &open[], 21 const double &high[], 22 const double &low[], 23 const double &close[], 24 const long &tick_volume[], 25 const long &volume[], 26 const int &spread[]) 27{ 28 return (rates_total); 29}

LineNotification.cpp

c++

1#include <curl/curl.h> 2 3#define MT4_EXPFUNC __declspec(dllexport) 4 5extern "C" 6MT4_EXPFUNC int __stdcall notifyLineAPI() 7{ 8 CURLcode ret; 9 CURL *hnd; 10 curl_mime *mime1; 11 curl_mimepart *part1; 12 struct curl_slist *slist1; 13 14 mime1 = NULL; 15 slist1 = NULL; 16 slist1 = curl_slist_append(slist1, "Authorization: Bearer <ACCESS_TOKEN>"); 17 18 hnd = curl_easy_init(); 19 curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L); 20 curl_easy_setopt(hnd, CURLOPT_URL, "https://notify-api.line.me/api/notify"); 21 curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, false); 22 curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L); 23 24 mime1 = curl_mime_init(hnd); 25 part1 = curl_mime_addpart(mime1); 26 27 curl_mime_data(part1, "ABC", CURL_ZERO_TERMINATED); 28 curl_mime_name(part1, "message"); 29 30 curl_easy_setopt(hnd, CURLOPT_MIMEPOST, mime1); 31 curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, slist1); 32 curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.67.0"); 33 curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); 34 curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS); 35 curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST"); 36 curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); 37 38 ret = curl_easy_perform(hnd); 39 40 curl_easy_cleanup(hnd); 41 hnd = NULL; 42 curl_mime_free(mime1); 43 mime1 = NULL; 44 curl_slist_free_all(slist1); 45 slist1 = NULL; 46 47 return (int)ret; 48}

c++のDLL化に使ったコマンド

PowerShell

1> mingw32-g++.exe LineNotification.cpp -l curl -o libLineNotification.dll "-Wl,-k,--output-def,DllLineNotification.def,--out-implib,libLineNotification.a"

試したこと

DLLのどこでエラーが発生しているのか確かめるために、LineNotifyAPIの中身を全てコメントアウトしreturn文だけ残し適当な数値を返させ、実行できるかどうか確かめました。これは、MT4で実行することができました。
一行ずつコメントアウトして確認したところ、最初に確認できた原因はslist1 = curl_slist_append(slist1, "Authorization: Bearer <ACCESS_TOKEN>");
この文で、Access Violationが起きているようでしたが、解決策がわかりませんでした。

補足情報(FW/ツールのバージョンなど)

libcurlに関しては、こちらのサイトにある誰かがビルド済みのものを使用しました。
https://curl.haxx.se/windows/

・curl for Windows 32bit

Specificaion欄の
・OpenSSL 1.1.1d [32bit]
・brotli 1.0.7 [32bit]
・libssh2 1.9.0 [32bit]
・nghttp2 1.39.2 [32bit]
・zlib 1.2.11 [32bit]

こちらをダウンロードしてMinGW直下に移動させました。

加えて
・Win32 OpenSSL v1.1.1d Light
をダウンロードしてProgram Files(x86)直下に保存しました。

ほかに必要な情報があればご指摘ください。

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

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

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

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

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

guest

回答1

0

ベストアンサー

curl_easy_initを一番最初に呼ぶように直してみてください。以下のように説明があるように、すべてのlibcurl API関数呼び出しの最初に呼ぶべきもののにように思えます。

curl_easy_init - url / libcurl / API / curl_easy_init

This function must be the first function to call,

今、そういうコードになっていないということで、libcurlライブラリ中の初期化されていない変数にアクセスし、 「Access violation」が発生してしまっているとしてもおかしくありません。ネットを検索してみると質問者さんのケースのようにcurl_slist_appendcurl_easy_initより先に呼ぶものも見かけましたが、API仕様からするとお行儀が悪いと思いますので、公式のサンプルや多くの実装例と同じようにしておくのが無難でしょう。

httpcustomheader.c - curl / libcurl / API / Examples / httpcustomheader.c

それと、現行の質問者さんのコードでは各種のlibcurl APIを使う際に実行後のチェックが行われていません。大抵の場合で恐らく大丈夫なはずでしょうが、プログラムの堅牢性やトラブルシューティングの面で困ると思いますので、可能な限りエラーチェックをした方が良いと考えます。ただこの点は本質問と回答の主旨ではありませんので、進言に留めます。

投稿2019/11/14 19:32

dodox86

総合スコア9183

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

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

SorasoSukhavati

2019/11/15 17:33

dodox86さん。 前回に引き続いてご回答ありがとうございました。 まさに、dodox86さんのおっしゃる通りで、curl_easy_init()関数を最初に呼び出したら、MT4から正しく実行することができました。標準ではないライブラリを使うのは初めてだったので、勝手がわかりませんでしたが、初期化の順番が違うだけで不具合が起きることも含め、仕様書をきちんと読むことの必要性を痛感しました。 エラーチェックのこともご指摘いただきありがとうございました。こちらもサンプルを確認しながら、追加していこうと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問