none
Declare での MarshalAs(UnmanagedType.)の取扱い RRS feed

  • 質問

  • いつもお世話になります。tom3.1063と申します。

    COBOLで作成されたDLLをVB.netから呼び出すプログラムを作成しております。

    VBのフォームで指定された伝票番号を引数に、関数(COBOLのDLL)を呼び出すと対応する伝票内容を表示する画面が表示されるといった具合です。

    Declareの引数にはString,Short,Integer,Single型の引数があります。

    Declareで、文字列の引数を「ByVal Para1 AS String」などと記述するとCOBOL側の仕様でしょうか?値が全角で引き渡されるようです。そこで「<MarshalAs(UnmanagedType.LPStr)> ByVal Para1 As String」と指定することで文字列に関しては回避できました。

    しかし、数値型は以下のように指定しても正常に引き渡されていないようでエラーが発生してしまいます。正確にはCOBOLのモジュールは呼び出せても、数値引数を使用するロジックが動作する時点でエラーになります。

     

    <MarshalAs(UnmanagedType.I2)> ByVal no As Short

    <MarshalAs(UnmanagedType.I4)> ByVal otime As Integer

    <MarshalAs(UnmanagedType.R4)> ByVal incd9 As Single

     

    エラー内容の抜粋

    「保護されているメモリに読み取りまたは書き込み操作を行なおうとしました。他のメモリが壊れていることが考えられます。」

     

    以上内容でヒントになるようなことがあればご教授いただければ幸いです。

    みなさんお忙しいところ恐縮ですが、よろしくお願いいたします。

     

    2006年8月21日 8:55

すべての返信

  • 回答をするのにはいささか情報が不足しているように思えます。

    少なくとも、その DLL 関数の定義(とかドキュメント)、また Declare 文そのものも書いてくれないと助言も困難です。

    // まあ私は COBOL は読めませんがー。

    呼び出し規約(CallingConvention)から疑わなくてはならないかも知れませんし。

    2006年8月21日 12:42
  • Hongliang 様ご指摘ありがとうございます。

    確かに情報不足しておりました。

    その後自己解決しましたのであわせて報告いたします。

    最終解決に至ったDeclare分の要約したものを以下に示します。

        Private Declare Auto Sub FINDSYOV Lib "I:\GANYLIB\PGM\FINDSYOV.DLL" ( _
                                 <MarshalAs(UnmanagedType.LPStr)> ByVal Para1 As String, _
                                 <MarshalAs(UnmanagedType.I2)> ByRef Para2 As Short, _
                                  <MarshalAs(UnmanagedType.I4)> ByRef Para3 As Integer, _
                                 <MarshalAs(UnmanagedType.R8)> ByRef Para4 As Double, _
                                  <MarshalAs(UnmanagedType.LPStr)> ByVal Para5 As String)

    改正内容は

    1. 数値項目のByVal指定だったものをByRef指定に変更。NetCobolのUSINGの指定で暗黙値がBY REFERENCEによるもの。

    2. Single指定をDoubleに変更。これはNetCobolの呼び出し規約がSingle指定となっていたのでそれに準じたのですが…。

    以上、NetCobol側仕様に依存する原因ばかりでした。みなさんには参考になる可能性が薄いかもしれませんが、ご報告いたします。

    2006年8月22日 1:03
  • 解決されたようなので蛇足ですが。

    Declareで、文字列の引数を「ByVal Para1 AS String」などと記述するとCOBOL側の仕様でしょうか?値が全角で引き渡されるようです。そこで「<MarshalAs(UnmanagedType.LPStr)> ByVal Para1 As String」と指定することで文字列に関しては回避できました。

    全角ではなく Unicode (2バイト文字体系) ですね。

    Declare ステートメント の解説にあるように、String からアンマネージドの文字列への変換に際して、Declare ステートメントでは Ansi/Unicode/Auto の三種類が選択できます。Ansi/Unicode に関してはそのままですが、Auto の場合は、関数名が A で終われば Ansi で、W で終われば Unicode で、そしてどちらでもなければプラットフォームに即した文字コード(9x 系なら Ansi、NT 系なら Unicode)が選択されます。もちろん MarshalAs 属性で文字コードを強制することもできますが。

    2006年8月22日 3:26
  • HongLiang様

     

    >全角ではなく Unicode (2バイト文字体系) ですね。

    ご指摘ありがとうございます。その点に関しては釈然としないままだったのですが、おかげさまで裏づけがとれました。

    またのご教授よろしくお願いいたします。

    2006年8月22日 8:45