プロが教える店舗&オフィスのセキュリティ対策術

お世話になっております。
以前も何度か似たような質問をさせて頂いたのですが
未だ解決に至りませんので、再度質問させていただきます。

現在、JavaからC++の自作dllを呼び出し、
C++dllから外部開発dllの関数を使いハードウェアへコマンドを送信する。
というプログラムを開発しております。

そこで、プログラムを動かし、終了させると
hs_pid...log が生成されます。
ログの内容(一部)↓
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x1a212cd2, pid=4716, tid=4332
#
# JRE version: 7.0_05-b05
# Java VM: Java HotSpot(TM) Client VM (23.1-b03 mixed mode windows-x86 )
# Problematic frame:
# C [PCardRW32.dll+0x22cd2] crwSetLineControl+0x203b2
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# C:\eclipse\workspace\ReWriteCard\hs_err_pid4716.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.sun.com/bugreport/crash.jsp
#
どうやら、メモリアクセス違反を起こしているみたいなのですが
logの内容は理解できません。

そこで、私が開発しましたプログラムを見て頂き、
BSTRの使い方がおかしいとのご指摘を受け、
しばらく調べていたのですが、どうにも改善できません。

C++のプログラム↓
JNI002_API jstring JNICALL Java_rewritecard_JNI001_DT(JNIEnv *env, jobject obj, jint jport) {
int port = (int)jport;
long int ret = 0;

test = crwOpenPort(port, 9600 , "8" , "N");

BSTR s1 = ::SysAllocString(L"s1");
BSTR s2 = ::SysAllocString(L"s2");
BSTR s3 = ::SysAllocString(L"s3");

ret = crwSendCommandRR(port,1,1000,1000,0,"DT",":1",2,&s1,&s2,&s3);

char* src = (char*)s3;

jstring jstr = env->NewStringUTF(src);

::SysFreeString(s1);
::SysFreeString(s2);
::SysFreeString(s3);

return jstr;
}

上記のプログラムのBSTRの使い方が悪いのは、承知致しておりますが
WideCharToMultiByte関数を使い、jstrへ変換し、
いかなる方法を試してもJava上で文字化けしますので
とりあえず今は現状で使用しております。

そこで試しに、以下のようなプログラムにしてみました
これだと、logファイルは生成されません。
JNI002_API jstring JNICALL Java_rewritecard_JNI001_DT(JNIEnv *env, jobject obj, jint jport) {
int port = (int)jport;
long int ret = 0;
/*
test = crwOpenPort(port, 9600 , "8" , "N");

BSTR s1 = ::SysAllocString(L"s1");
BSTR s2 = ::SysAllocString(L"s2");
BSTR s3 = ::SysAllocString(L"s3");

ret = crwSendCommandRR(port,1,1000,1000,0,"DT",":1",2,&s1,&s2,&s3);

char* src = (char*)s3;

jstring jstr = env->NewStringUTF(src);

::SysFreeString(s1);
::SysFreeString(s2);
::SysFreeString(s3);
*/
jstring jstr = env->NewStringUTF("");

return jstr;
}


しかし、以下のようにすると
logファイルが生成されます。

JNI002_API jstring JNICALL Java_rewritecard_JNI001_DT(JNIEnv *env, jobject obj, jint jport) {
int port = (int)jport;
long int ret = 0;

test = crwOpenPort(port, 9600 , "8" , "N");
/*
BSTR s1 = ::SysAllocString(L"s1");
BSTR s2 = ::SysAllocString(L"s2");
BSTR s3 = ::SysAllocString(L"s3");

ret = crwSendCommandRR(port,1,1000,1000,0,"DT",":1",2,&s1,&s2,&s3);

char* src = (char*)s3;

jstring jstr = env->NewStringUTF(src);

::SysFreeString(s1);
::SysFreeString(s2);
::SysFreeString(s3);
*/
jstring jstr = env->NewStringUTF("");
return jstr;
}

だとすると、logとBSTRの問題は別物だと判断してもいいんでしょうか
また、Java → 自作dll → 他社dll という構図に問題があるんでしょうか
ささいなことでも構いません
ご教授宜しくお願い致します。

A 回答 (4件)

>さきほどのログは、C++のプログラムをビルドした時のログです。


>私が作成しました、JNI001のプログラムは、DT以外にもメソッド、と言っていいんでしょうか
>メソッドがありますので、DT以外の警告だと思います。

それならそれでJava_rewritecard_JNI001_DT以外の関数のコンパイルログを省略する方が・・・
Java_rewritecard_JNI001_DTのコンパイル時の警告を確認したかったのに今まで話にも出てこなかった他の部分のコンパイルログを抜粋されても判断に困るわけですが。

>extern DllImport short int WINAPI crwOpenPort(short int, LONG, LPCSTR, LPCSTR);
>extern DllImport short int WINAPI crwSendCommandRR(short int,
>short int,
>LONG,
>LONG,
>short int,
>LPCTSTR,
>LPCTSTR,
>short int,
>BSTR*,
>BSTR*,
>BSTR* );

これ書き間違えとかはないですか?
crwOpenPortでは引数にLPCSTRが使われていて、crwSendCommandRRでは引数にLPCTSTRが使われているというのは統一性に欠けるというか・・・
とりあえずこれがあってるのであれば少なくともcrwOpenPortの使い方は間違ってないと思いますので、それでjavaがログを出力するということは私が思いつくところでは
・javaがスレッドに割り当てているスタック領域をcrwOpenPortが食いつぶしている
・実はcrwOpenPortは再入不可で、再入された
くらいです。

>それとひとつ気になったんですが
>C++のプロジェクトのプロパティで、文字セットの設定を
>設定なしにしてるんですが、こちらは関係ないでしょうか。

crwSendCommandRRの引数にLPCTSTRがあるので関係すると思いますがプロトタイプ宣言からの推測でしかないので他社性DLLの提供元に確認してみてください。
    • good
    • 0
この回答へのお礼

考えが及んでおりませんでした。
せっかくのご助言、無駄にするような行い
大変申し訳ありません。

関数の書き間違えについては、間違いではないようです。
確認致しましたが、記載どおりでした。

では、
・javaがスレッドに割り当てているスタック領域をcrwOpenPortが食いつぶしている
・実はcrwOpenPortは再入不可で、再入された
こちらの2つの状況を調べてみます。

困り果てておりましたので大変助かりました。
ありがとうございました。

お礼日時:2012/07/24 09:32

>正常終了となっていますし、


>引数として渡されるintは、shortを超える数字ではないので、
>良いかなと思い無視しておりましたが、これらの警告は無視できないものなんでしょうか

「引数として渡されるintは、shortを超える数字ではないので、」
こういった理由がある分には無視するのはかまわないです。
無視していないかどうか尋ねたのは、無視してはいけない警告を無視してないかどうかなので。

ところでこのコンパイルのログは何をコンパイルしたものなんでしょうか?
質問文に書かれているJava_rewritecard_JNI001_DT()のコンパイルログにしては

>jstring jstr = env->NewStringUTF(src);

関数内でenvは使われているのに

>1>JNI002.cpp(16): warning C4100: 'env' : 引数は関数の本体部で 1 度も参照されません。

という警告が出てるのが不思議なんですけど。

もし可能であれば
crwOpenPort(), crwSendCommandRR()
のプロトタイプ宣言教えていただけませんか?

この回答への補足

ご回答ありがとうございます。
さきほどのログは、C++のプログラムをビルドした時のログです。
私が作成しました、JNI001のプログラムは、DT以外にもメソッド、と言っていいんでしょうか
メソッドがありますので、DT以外の警告だと思います。

プロトタイプ宣言、意味をはき違えてましたら申し訳ないですが
こちらでよろしいでしょうか。


extern DllImport short int WINAPI crwOpenPort(short int, LONG, LPCSTR, LPCSTR);


extern DllImport short int WINAPI crwSendCommandRR(short int,
short int,
LONG,
LONG,
short int,
LPCTSTR,
LPCTSTR,
short int,
BSTR*,
BSTR*,
BSTR* );

それとひとつ気になったんですが
C++のプロジェクトのプロパティで、文字セットの設定を
設定なしにしてるんですが、こちらは関係ないでしょうか。

お手数おかけしますが、宜しくお願いいたします。

補足日時:2012/07/23 09:22
    • good
    • 0

>関数の使い方


>ということに関して、dllを開発した会社へプログラムを見て頂き、
>問い合わせを行ったところ
>BSTRの使い方がおかしいとの指摘を頂きました。

確かにBSTRの使い方におかしいところはあると思うんですが(私はBSTRは使ったことないのでMSDNにあるドキュメントを読んだだけですが)

http://msdn.microsoft.com/ja-jp/library/xda6xzx7 …

ただ、いくらBSTRの使い方がおかしいにしてもワイド文字列が設定されるところにマルチバイト文字列が設定されて返ってきてる事もおかしいんです。

他にも気になってる事があって

>ret = crwSendCommandRR(port,1,1000,1000,0,"DT",":1",2,&s1,&s2,&s3);

第9~11引数にはBSTRのポインタを要求していながら第6, 第7引数がマルチバイト文字列というのも不思議な気がしてます。

もしかして他社製DLLを使用するためのヘッダファイルをインクルードしていなかったり、コンパイル時の警告を無視していたりしませんか?

この回答への補足

ご回答ありがとうございます。
さきほど、C++のプログラムを確認いたしました。
インクルードはできております。
インクルードしていなかったら、関数を指定するときに、エラーが出ますので
できていると思うんですが、
コンパイル時の警告に関しては
さきほど、C++の警告レベルがレベル3だったのを、レベル4に変えて
コンパイルしなおしてみました。
以下が実行結果の出力です。


1>------ ビルド開始: プロジェクト: JNI002, 構成: Release Win32 ------
1> stdafx.cpp
1> dllmain.cpp
1>dllmain.cpp(7): warning C4100: 'lpReserved' : 引数は関数の本体部で 1 度も参照されません。
1>dllmain.cpp(4): warning C4100: 'hModule' : 引数は関数の本体部で 1 度も参照されません。
1> JNI002.cpp
1>JNI002.cpp(16): warning C4100: 'obj' : 引数は関数の本体部で 1 度も参照されません。
1>JNI002.cpp(16): warning C4100: 'env' : 引数は関数の本体部で 1 度も参照されません。
1>JNI002.cpp(53): warning C4244: '引数' : 'int' から 'short' への変換です。データが失われる可能性があります。

・ 文字数制限のため割愛致します
・ 場所が違うのみで、エラー内容は同じです(割愛分56行)


1>JNI002.cpp(425): warning C4100: 'obj' : 引数は関数の本体部で 1 度も参照されません。
1>JNI002.cpp(425): warning C4100: 'env' : 引数は関数の本体部で 1 度も参照されません。
1> ライブラリ C:\username\username\Documents\Visual Studio 2010\Projects\JNI002\Release\JNI002.lib とオブジェクト C:\username\username\Documents\Visual Studio 2010\Projects\JNI002\Release\JNI002.exp を作成中
1> コード生成しています。
1> コード生成が終了しました。
1> JNI002.vcxproj -> C:\username\username\Documents\Visual Studio 2010\Projects\JNI002\Release\JNI002.dll
========== ビルド: 1 正常終了、0 失敗、0 更新不要、0 スキップ ==========

そして、これが完了した後
プログラム C:\パス・・・\JNI002.dllを開始できません
というポップアップが出てOKボタンをクリックします。

正常終了となっていますし、
引数として渡されるintは、shortを超える数字ではないので、
良いかなと思い無視しておりましたが、これらの警告は無視できないものなんでしょうか

補足日時:2012/07/21 13:34
    • good
    • 0

>そこで、私が開発しましたプログラムを見て頂き、


>BSTRの使い方がおかしいとのご指摘を受け、
>しばらく調べていたのですが、どうにも改善できません。

何か勘違いされてるようなんですが私は「BSTRの使い方がおかしい」とはいってませんよ?
「他社製DLLの使い方を間違ってないか確認した方がよいと思いますよ」と書いてたはずですが。
少なくともcrwSendCommandRR()の第9~11引数はBSTRへのポインタを要求するにしてはマルチバイト文字列へのアドレスが格納されて返ってくる事がおかしいんです(BSTRが扱うのはワイド文字列)
で、crwSendCommandRR()をはじめとする他社製DLLが提供している関数の使い方が正しいのか間違ってるのかは、その仕様を知らない私らには判断できません。
なのでその他社製DLLの提供元に関数の使い方を確認することをお勧めします(以前からいってる)。

この回答への補足

説明不足でありました。
お気を悪くされたようですね。
大変申し訳ないです。

wormholeさんから指摘して頂いた
関数の使い方
ということに関して、dllを開発した会社へプログラムを見て頂き、
問い合わせを行ったところ
BSTRの使い方がおかしいとの指摘を頂きました。
そのほかにも、教えてGooにて、wormholeさんではない方から、
BSTRの使い方がおかしいと指摘をいただきました。

説明不足、大変申し訳ありません

補足日時:2012/07/21 09:03
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!