C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

ログ内検索
  • キーワードを複数指定する場合は 半角スペース で区切ってください。
  • 検索条件は、(AND)=[A かつ B] (OR)=[A または B] となっています。
  • [返信]をクリックすると返信ページへ移動します。
キーワード/ 検索条件 /
検索範囲/ 強調表示/ ON (自動リンクOFF)
結果表示件数/ 記事No検索/ ON
大文字と小文字を区別する

全過去ログを検索

<< 0 | 1 >>
■27288  Re[1]: コマンドプロンプトで.NET Framworkの確認について
□投稿者/ やじゅ -(2008/11/02(Sun) 11:08:40)
>
    No27287 (あら さん) に返信
    > OSはXP or Vistaで.NET Framwork 3.0SP1と中国、韓国語のランゲージパック
    > がインストールされているかどうかをコマンドプロンプトで判断したいと思
    > っています。
    >

    プログラムの追加と削除に存在すればインストールされていると判断しても
    いいのかなと思ってます。
    レジストリを見ることになりますけどね、WMIのWin32_Productクラスだと
    環境によっては駄目なようですので。

    参照先:

    Windowsの「プログラムの追加と削除」に表示されるプログラム名を取得するスクリプト
    http://d.hatena.ne.jp/htada/20060906/1157530685

    【プログラムの追加と削除】に表示される情報を取得
    http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=1428644&SiteID=7

    Windows Server 2003とWindows Vistaは標準でWMIコンポーネントの一部がインストールされていない。
    Win32_Productクラスもその一つらしくWMI経由でのクエリが失敗する。
    http://d.hatena.ne.jp/Kazzz/20070528/p1

    NET Frameworkのバージョンを確認する方法
    http://www.atmarkit.co.jp/fwin2k/win2ktips/246checkvdnfw/checkvdnfw.html
記事No.27287 のレス /過去ログ50より / 関連記事表示
削除チェック/

■50241  Re[1]: グローバルフック
□投稿者/ 甕星 -(2010/05/31(Mon) 20:52:59)
    管理者権限が無い状態で起動しているか、ChangeWindowMessageFilter APIを呼び出して許可する必要があるか、どちらかじゃないかと思います。
記事No.50230 のレス /過去ログ85より / 関連記事表示
削除チェック/

■66284  JSP表示
□投稿者/ マミー -(2013/04/12(Fri) 16:51:02)

    分類:[Java] 

    こんにちは。DBから取得 JSPに表示を勉強しています。
    条件が 列指定 前方指定 昇順降順などあり
    列ごとに取得 表示といった形で表示することができました
    ただこれだと 横に表示されるのですが、どうすれば縦に表示できるように
    組みなおせますか?それかこの組み方だとHTMLでがんばったほうが良いのでしょうか?アドバイスお願いします


    JSP(検索、表示)
    <table border>
    <tr>
    <td>
    検索内容 TESTNO <input type="checkbox" name="TESTNO" value="TESTNO"
    </td>
    <td>
    NAME <input type="checkbox" name="NAME" value="NAME" >
    </td>
    <td>
    KANA <input type="checkbox" name="KANA" value="KANA" >
    </td>
    </tr>
    </table border>
    <table border>
    <tr>
    <td>
    検索条件 <input type="text" name="name" >(NAME前方一致)
    </td>
    </table>

    <table border>
    <tr><td>
    ソート   <select name="menu">
    <option value=TESTNO>TESTNO</option>
    <option value=NAME>NAME</option>
    <option value=KANA>KANA</option>
    </select>

    <input type="radio" name="narabi" value="ASC" /> 昇順
    <input type="radio" name="narabi" value="DESC"/> 降順
    </td></tr>
    </table>

    <br><input type="submit" value="検索">
    </from>
    </body>
    </form>

    <Hr>

    <%
    if(request.getAttribute("list")!=null || request.getAttribute("list1")!=null || request.getAttribute("list2")!=null){


    if(request.getAttribute("list")!=null){
    List list=(List)request.getAttribute("list");
    for(int i=0; i<list.size(); i++){
    out.print(list.get(i)+" ");
    }
    }
    %><br>
    <%

    if(request.getAttribute("list1")!=null){
    List list1=(List)request.getAttribute("list1");
    for(int i=0; i<list1.size(); i++){
    out.print(list1.get(i)+" ");
    }
    }
    %><br>
    <%
    if(request.getAttribute("list2")!=null){
    List list2=(List)request.getAttribute("list2");
    for(int i=0; i<list2.size(); i++){
    out.print(list2.get(i)+" ");
    }
    }
    %><br>

    サーブレット(取得、フォワードで転送)

    String name=request.getParameter("name");
    //NAMEの前方一致条件取得
    String narabi=request.getParameter("narabi");
    //降順、昇順、の値取得
    String menu=request.getParameter("menu");
    //昇順、降順するところの列 name取得



    db.updateExec("insert into TESTTABLE1(TESTNO,NAME,KANA) values("+1+",'山田', 'ヤマダ')");
    db.updateExec("insert into TESTTABLE1(TESTNO,NAME,KANA) values("+2+",'佐藤', 'サトウ')");
    ・・・・・・
    //課題のため10行入力


    db.commit(); //コミットして 確定

    ArrayList list;
    ArrayList list1;
    ArrayList list2;
    //リスト作成



    if(narabi!=null){//昇順 降順にチェックがあるか判断
    String[][]hai4=db.selectExec("SELECT * FROM TESTTABLE1 WHERE NAME LIKE'"+name+"%' order by "+menu+" "+narabi+" ;");
    //nameで前方一致 menuで昇順降順場所 narabiで降順昇順

    list = new ArrayList(Arrays.asList(hai4[0]));
    list1 = new ArrayList(Arrays.asList(hai4[1]));
    list2= new ArrayList(Arrays.asList(hai4[2]));

    }else{//昇順降順なければこっち

    String[][]hai3=db.selectExec("SELECT * FROM TESTTABLE1 WHERE NAME LIKE'"+name+"%';");
    //nameで前方一致

    list = new ArrayList(Arrays.asList(hai3[0]));
    list1 = new ArrayList(Arrays.asList(hai3[1]));
    list2 = new ArrayList(Arrays.asList(hai3[2]));

    }

    if (request.getParameter("TESTNO") != null){
    request.setAttribute("list", list);
    }

    if (request.getParameter("NAME") != null){
    request.setAttribute("list1", list1);
    }

    if (request.getParameter("KANA") != null){
    request.setAttribute("list2", list2);
    }


    結果

    1 2 3 4 5 6 7 8 9 10
    山田 佐藤 山本 伊藤 武田 鈴木 小野 松井 田中 高橋
    ヤマダ サトウ ヤマモト イトウ タケダ スズキ オノ マツイ タナカ タカハシ

    1 山田 ヤマダ
    2 佐藤 サトウ
    ・・・・・・
    といった表示にしたいです
    行ごとに取得して繰り返すのがいいのかなと思って最初やていたのですが
    列指定したときに エラー(指定listがない)といったようになるので
    この組み方にしました。
    アドバイスお願いします

    ひとつ前に作成したのものせます

    if(request.getAttribute("list")!=null || request.getAttribute("list1")!=null || request.getAttribute("list2")!=null){
    for(int i=0; i<10; i++){

    if(request.getAttribute("list")!=null){
    List list=(List)request.getAttribute("list");
    out.print(list.get(i)+" ");
    }
    if(request.getAttribute("list1")!=null){
    List list1=(List)request.getAttribute("list1");
    out.print(list1.get(i)+" ");
    }
    if(request.getAttribute("list2")!=null){
    List list2=(List)request.getAttribute("list2");
    out.println(list2.get(i));
    }

    ↑は リストのどれかが空だとエラーがでろのと、list.sizeで長さが取れないなとおもい、あきらめました・・・
    list.sizeっで指定したリストが空の場合があるので><

親記事 /過去ログ112より / 関連記事表示
削除チェック/

■75306  VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ とら -(2015/03/12(Thu) 19:36:57)

    分類:[VB.NET/VB2005 以降] 

    2015/03/12(Thu) 19:55:24 編集(投稿者)
    2015/03/12(Thu) 19:54:46 編集(投稿者)
    2015/03/12(Thu) 19:54:40 編集(投稿者)

    <pre><pre>VB6.0で作成した実行ファイルからVC++6.0で作成したDLLに値を参照渡ししているものがあり、
    このたびVB.net2008にアップグレードする事になりました。(なぜ2013ではないのかは置いといてください)

    アップグレードウィザードを通してエラーや警告を除外した後に動作確認をしたところ、DLLの呼出し時に
    予期せぬ動作が起きていて詰まっています。

    DLLを呼び出す際に構造体の配列を参照渡ししているのですが、配列を10で作成し参照渡しして
    戻ってきた配列が1つになってしまいます。

    色々調べてみたところ、値渡しにすると大丈夫(配列なのでそもそも参照型だから参照の値渡しになる)
    といった記述があったので試してみたのですが、配列は10のままで戻ってくるようになったのですが、
    値が格納されていません。


    解決策をご存じの方、お教え頂けないでしょうか。


    以下ソースになります。


    -- 宣言部 ----

    Declare Function Test1 Lib "TestFunc.DLL" (ByRef oStructure() as Structure1) as Integer


    Public Structure Structure1
    Dim int1 As Integer
    Dim int2 As Integer
    Dim int3 As Integer
    End Structure


    '配列の作成(10個の配列として宣言)
    Public oStructure1(9) As Structure1


    -- 処理 ----

    'DLLの呼出し
    Dim iRet as integer = -1
    iRet = Test1(oStructure1)

    '呼出し後に参照で渡した(oStructure1)の数が1つになっている



    ・構造体の中身はすべてInt型です。
    ・BV6.0で作成したモジュールからは正常に取得できています。
    ・VC++6.0のDLLは変更しない方向で決定なので、DLLには手を加える事ができません
    ・VC++6.0側が配列を受け取った時点で1つになっています。



    以上、よろしくお願いします。
親記事 /過去ログ127より / 関連記事表示
削除チェック/

■75309  Re[1]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ 魔界の仮面弁士 -(2015/03/12(Thu) 21:22:29)
    No75306 (とら さん) に返信
    > VB6.0で作成した実行ファイルからVC++6.0で作成したDLLに値を参照渡ししているものがあり、
    > このたびVB.net2008にアップグレードする事になりました。

    この文章だけだと、VB6 EXE から VB2008 DLL を呼ぶ方向にも読み取れてしまいますね。

    なお、製品名に .NET の名を冠するのは 2003までなので、
    正確には、VB.net2008 → VB2008 だったりしますが、それはさておき。


    > アップグレードウィザードを通してエラーや警告を除外した後に

    提示されたコードは恐らく、実際のコードとは別物ですよね。
    (実コードを貼り付けたなら、as が小文字表記されているはずが無いので…)

    「改修に失敗している現在のコード」だけではなく、
    「正常動作している改修前のコード」も提示していただけないでしょうか。
    もしくは DLL 側のコードでも良いですけど。


    自分が、VB6 でそのような DLL を呼び出すとすれば、
     Declare Function Test1 Lib "TestFunc" (ByRef oStructure As Structure1) As Long
     Dim udt(9) As Structure1
     ret = Test1( udt(0) )
    もしくは
     Declare Function Test1 Lib "TestFunc" (ByVal oStructure As Long) As Long
     Dim udt(9) As Structure1
     ret = Test1( VarPtr( udt(0) ) )
    で実装することが多いのですが、とらさんの提示された(改修後の)コードは
    構造体配列の参照渡しになっているようですし…。


    実際に検証してみたいところですが、現状は情報不足のため、以下、思いつきで回答。
    未検証ゆえ、正しい内容であるかどうかは保証できませんが。


    > Public Structure Structure1
    構造体には StructLayoutAttribute を明示しておくことをお奨めします。
    たとえば、その DLL のパッキングサイズが 4 バイト単位なら、
    『<StructLayout(LayoutKind.Sequential, Pack:=4)>』など。


    > '呼出し後に参照で渡した(oStructure1)の数が1つになっている
    引数に MarshalAsAttribute を付与しておいてください。
    SizeConst が指定されていない場合、マーシャリングされるのは 1 つの要素だけだったはず。



    > 色々調べてみたところ、値渡しにすると大丈夫(配列なのでそもそも参照型だから参照の値渡しになる)
    > といった記述があったので試してみたのですが、配列は10のままで戻ってくるようになったのですが、
    > 値が格納されていません。
    配列を値渡しした場合、それは In パラメーターとしてマーシャリングされるためかと。
    結果を受け取る必要があるのなら、<InAttribute(), OutAttribute()> を付与しておいてください。

    https://msdn.microsoft.com/ja-jp/library/hk9wyw21.aspx
記事No.75306 のレス /過去ログ127より / 関連記事表示
削除チェック/

■75310  Re[2]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ とら -(2015/03/12(Thu) 21:59:05)
    No75306 (魔界の仮面弁士 さん) に返信


    >>VB6.0で作成した実行ファイルからVC++6.0で作成したDLLに値を参照渡ししているものがあり、
    >>このたびVB.net2008にアップグレードする事になりました。
    >
    > この文章だけだと、VB6 EXE から VB2008 DLL を呼ぶ方向にも読み取れてしまいますね。
    >
    > なお、製品名に .NET の名を冠するのは 2003までなので、
    > 正確には、VB.net2008 → VB2008 だったりしますが、それはさておき。

    なるほど、以後留意致します。



    >>アップグレードウィザードを通してエラーや警告を除外した後に
    >
    > 提示されたコードは恐らく、実際のコードとは別物ですよね。
    > (実コードを貼り付けたなら、as が小文字表記されているはずが無いので…)
    >
    > 「改修に失敗している現在のコード」だけではなく、
    > 「正常動作している改修前のコード」も提示していただけないでしょうか。
    > もしくは DLL 側のコードでも良いですけど。

    アップグレードとエラー及び警告の対応は他の方がされていたので少々混乱しておりました。

    アップグレード前のVB6.0の該当部分のソースになります。

    -- 宣言部 ----

    Declare Function Test1 Lib "TestFunc.DLL" (oStructure() As Any) As Long

    Public Structure Structure1
    Dim int1 As Long
    Dim int2 As Long
    Dim int3 As Long
    End Structure


    '配列の作成(10個の配列として宣言)
    Public oStructure1(0 To 9) As Structure1


    -- 処理 ----

    'DLLの呼出し
    Dim iRet as integer = -1
    iRet = Test1(oStructure1())


    >> Public Structure Structure1
    > 構造体には StructLayoutAttribute を明示しておくことをお奨めします。
    > たとえば、その DLL のパッキングサイズが 4 バイト単位なら、
    > 『<StructLayout(LayoutKind.Sequential, Pack:=4)>』など。
    >
    >> '呼出し後に参照で渡した(oStructure1)の数が1つになっている
    > 引数に MarshalAsAttribute を付与しておいてください。
    > SizeConst が指定されていない場合、マーシャリングされるのは 1 つの要素だけだったはず。
    >
    >>色々調べてみたところ、値渡しにすると大丈夫(配列なのでそもそも参照型だから参照の値渡しになる)
    >>といった記述があったので試してみたのですが、配列は10のままで戻ってくるようになったのですが、
    >>値が格納されていません。
    > 配列を値渡しした場合、それは In パラメーターとしてマーシャリングされるためかと。
    > 結果を受け取る必要があるのなら、<InAttribute(), OutAttribute()> を付与しておいてください。


    取り急ぎ、宣言部を下記のようにByValに変更し<InAttribute(), OutAttribute()> を付与してみましたが
    配列数は10になったものの値は変わっていませんでした。

    Imports System.Runtime.InteropServices

    Declare Function Test1 Lib "TestFunc.DLL" (<InAttribute(), OutAttribute()> ByVal oStructure() As Structure1) As Long



    確認は明日になりますが、引き続き宜しくお願い致します。
記事No.75306 のレス /過去ログ127より / 関連記事表示
削除チェック/

■75311  Re[3]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ 魔界の仮面弁士 -(2015/03/13(Fri) 01:21:10)
    No75310 (とら さん) に返信
    > Declare Function Test1 Lib "TestFunc.DLL" (oStructure() As Any) As Long
    > Public Structure Structure1
    > Dim int1 As Long
    > Dim int2 As Long
    > Dim int3 As Long
    > End Structure
    > Dim iRet as integer = -1

    上記は何のコードでしょうか?

    Dim 宣言部で値を挿入していることから、VB2008 のようにも見えますが、
    VB.NET に「Any」は無いはずです。別途 Class Any などを作ってあるなら別ですが。


    > アップグレード前のVB6.0の該当部分のソースになります。
    VB6 に「Structure」という宣言はありませんし、どうみても文法エラーです。
    できるだけ実際の状況に即したコードの提示をお願いします。


    もし、元のコードをそのまま提供することに問題があるのであれば、
    『第三者が現象を再現できる最小限の実験用コード』を提示してみてください。
    質問内容がぶれたままだと回答側もキツイです…。


    > Declare Function Test1 Lib "TestFunc.DLL" (<InAttribute(), OutAttribute()> ByVal oStructure() As Structure1) As Long

    戻り値の型も変更されたのですか?
    もし、旧VB で As Long なのだとしたら、.NET 側では Int32 。最初の投稿通りの As Integer で良いですよ。

    もしも本当に 64bit整数型 を扱っていたのだとしても(GetDiskFreeSpaceEx API など)、
    当時それに見合う型は Currency ぐらいしかなかったはずです。
    (7.0 以降であれば、VB.NET の As Long に相当する As LongLong があったりしますが)



    > 取り急ぎ、宣言部を下記のようにByValに変更し<InAttribute(), OutAttribute()> を付与してみましたが
    > 配列数は10になったものの値は変わっていませんでした。

    ByVal oStructure() As Structure1 な引数で呼び出してみましたが、
     Out 属性なし → 呼び出し前後で引数の内容は変化しない。(DLL 側に値は渡っている)
     Out 属性あり → 呼び出し後に、DLL で書き換えた構造体値が反映されている。
    ということで、当方では問題ないことを確認しています。


    なお、とらさんの DLL がどういう実装になっているのか説明が無かったので、
    ひとまず int __stdcall Test1(Structure1 *a); な実装で実験しています。
    (手元に VC++6.0 はないので、2010 を用いています)
記事No.75306 のレス /過去ログ127より / 関連記事表示
削除チェック/

■75307  Re[1]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ Hongliang -(2015/03/12(Thu) 20:15:53)
    C++の関数/構造体定義も見ないとはっきりとは断言できませんが…。

    > (ByRef oStructure() as Structure1) as Integer
    はByValになるはずです。

    > 構造体の中身はすべてInt型です。
    Int型って何でしょう? VBならIntegerですし、C++ならint型(C/C++は大文字小文字を区別する)です。
    VBでもVB6までとそれ以降では別物です。

    > 呼出し後に参照で渡した(oStructure1)の数が1つになっている
    「(oStructure1)の数」というのは、どうやって確認した物ですか?
記事No.75306 のレス /過去ログ127より / 関連記事表示
削除チェック/

■75308  Re[2]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ とら -(2015/03/12(Thu) 20:22:17)
    説明不足が結構ありました、すみません


    >>(ByRef oStructure() as Structure1) as Integer
    > はByValになるはずです。

    値渡しのByValにして配列が10個で戻ってくる事は確認しました。
    ただ、戻ってきた配列の中身を確認したところ、値が変化していませんでした。


    >>構造体の中身はすべてInt型です。
    > Int型って何でしょう? VBならIntegerですし、C++ならint型(C/C++は大文字小文字を区別する)です。
    > VBでもVB6までとそれ以降では別物です。

    Int型というかInteger型です、省略してすみません


    >>呼出し後に参照で渡した(oStructure1)の数が1つになっている
    > 「(oStructure1)の数」というのは、どうやって確認した物ですか?

    VC++6.0をデバッグ実行し確認しました。


    以上、引き続きお願い致します。
記事No.75306 のレス /過去ログ127より / 関連記事表示
削除チェック/

■75312  Re[3]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ 魔界の仮面弁士 -(2015/03/13(Fri) 09:36:15)
    No75308 (とら さん) に返信
    >>>呼出し後に参照で渡した(oStructure1)の数が1つになっている
    >>「(oStructure1)の数」というのは、どうやって確認した物ですか?
    > VC++6.0をデバッグ実行し確認しました。

    VB EXE 側ではなく、VC++ DLL 側のデバッガで要素数を確認されたのでしょうか。

    今回の配列って、VB 側でメモリ確保されたものですよね。

    配列要素の先頭要素をアドレス渡ししているのだとしたら、
    C++ 側では要素数は分からないように思うのですが、違うのかな。


    もし、引数が C スタイルの配列ではなく、COM の SAFEARRAY で宣言されていたなら
    C++ 側で要素数を確認することもできるでしょうけれども、その場合、VB6 では
    「Type ステートメントで型定義されたユーザー定義型」の配列ではなく、
    「タイプライブラリにて型定義された構造体」の配列になっていたはず。

    でも、実際にはそうでは無かったのですよね…?
記事No.75306 のレス /過去ログ127より / 関連記事表示
削除チェック/

■75314  Re[4]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ とら -(2015/03/13(Fri) 11:28:42)
    No75312 (魔界の仮面弁士 さん) に返信

    お手数をお掛けして申し訳御座いません。
    再度徹底して見直してまとめなおしました。


    >VB EXE 側ではなく、VC++ DLL 側のデバッガで要素数を確認されたのでしょうか。
    VB2008側及びVC++側のデバッグ双方にて確認致しました。
    VCで受け取った際に既に要素数が1個になっていたようなのでVB2008側での問題だと思いました。



    VC++6.0側は内容が理解できなかったのでメソッドの宣言部のみです

    VC++6.0側のType1に関しては、「受信データを格納する構造体へのポインタ
    または受信データを格納した共有メモリの管理構造体へのポインタ」
    と記載がありました


    ## VC++6.0 ###########

    Test1_API int __stdcall Test1(LPSAFEARRAY *Type1)


    ## VB6.0 #############

    -- 宣言部 ----

    Declare Function Test1 Lib "TestFunc.DLL" (oType() As Any) As Long

    Public Type Type1
    Long1 As Long
    Long2 As Long
    Long3 As Long
    End Type

    Public oType(0 To 9) As Type1


    -- 処理 ----

    Dim iRet As Long
    iRet = Test1(oType())



    ## VB2008 アップグレード後にエラー及び警告を排除した状態で渡されたソース #############

    -- 宣言部 ----

    Declare Function Test1 Lib "TestFunc.DLL" (ByRef oStructure() As Structure1) As Integer

    Public Structure Structure1
    Dim int1 As Integer
    Dim int2 As Integer
    Dim int3 As Integer
    End Structure

    Public oStructure1(9) As Structure1


    -- 処理 ----

    Dim iRet As integer = -1
    iRet = Test1(oStructure1)

    '結果としては配列の要素数が1個になっており、値も変更されていない



    ## VB2008 ご指摘部分反映後 #############


    '参照渡しを値渡しに変更しマーシャリングを追加

    Imports System.Runtime.InteropServices

    Declare Function Test1 Lib "TestFunc.DLL" (<InAttribute(), OutAttribute()> ByVal oStructure() As Structure1) As Integer

    '結果としては配列の要素数は10個になったものの値は変更されていない



    以上、引き続きお願い致します。
記事No.75306 のレス /過去ログ127より / 関連記事表示
削除チェック/

■75321  Re[5]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ 魔界の仮面弁士 -(2015/03/13(Fri) 15:08:55)
    No75314 (とら さん) に返信
    > Test1_API int __stdcall Test1(LPSAFEARRAY *Type1)
    そっちでしたか! まさかと思ったら、本当にセーフ配列だったという。(^_^;


    > VC++6.0側は内容が理解できなかったのでメソッドの宣言部のみです
    私も C++ は専門外(というかホボ素人)なので、そこまで想像が追いつきませんでした。
    ユーザー定義型の配列を SAFEARRAY でやりとしたことは無いんですよね…。


    > Declare Function Test1 Lib "TestFunc.DLL" (ByRef oStructure() As Structure1) As Integer

    MarshalAs 指定は必要になるだろうということで、SafeArray 指定で
     ・SafeArray
     ・SafeArray, SafeArraySubType:=VT_USERDEFINED
     ・SafeArray, SafeArraySubType:=VT_RECORD, SafeArrayUserDefinedSubType:=GetType(Structure1)
    などを試してみましたが、HRESULT が E_INVALIDARG(0x80070057) を返すばかり。

    LPArray でも試してみましたが、
     ・LPArray, ArraySubType:=AsAny
     ・LPArray, ArraySubType:=LPStruct
     ・LPArray, ArraySubType:=Struct
    実行はできるものの、配列が 1 個になってしまう様子。

    かといってここに SizeConst や SizeParamIndex を指定すれば、
    MarshalDirectiveException が発生するという状況。


    はてさて…。

    https://msdn.microsoft.com/ja-jp/library/z6cfh6e6.aspx
記事No.75306 のレス /過去ログ127より / 関連記事表示
削除チェック/

■75332  Re[6]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ とら -(2015/03/16(Mon) 14:18:00)
    No75321 (魔界の仮面弁士 さん) に返信

    >>Test1_API int __stdcall Test1(LPSAFEARRAY *Type1)
    > そっちでしたか! まさかと思ったら、本当にセーフ配列だったという。(^_^;

    すみません、VC++との連携自体が初なので、どの程度情報が必要なのかもよく理解しておりませんでした。


    >>Declare Function Test1 Lib "TestFunc.DLL" (ByRef oStructure() As Structure1) As Integer
    >
    > MarshalAs 指定は必要になるだろうということで、SafeArray 指定で
    >  ・SafeArray
    >  ・SafeArray, SafeArraySubType:=VT_USERDEFINED
    >  ・SafeArray, SafeArraySubType:=VT_RECORD, SafeArrayUserDefinedSubType:=GetType(Structure1)
    > などを試してみましたが、HRESULT が E_INVALIDARG(0x80070057) を返すばかり。

    > LPArray でも試してみましたが、
    >  ・LPArray, ArraySubType:=AsAny
    >  ・LPArray, ArraySubType:=LPStruct
    >  ・LPArray, ArraySubType:=Struct
    > 実行はできるものの、配列が 1 個になってしまう様子。
    >
    > かといってここに SizeConst や SizeParamIndex を指定すれば、
    > MarshalDirectiveException が発生するという状況。

    マーシャリング自体もよく理解しておらず、私の方でも調査しているものの難航しております。


    引き続き他の方々もご存知の方がおられましたらご回答頂ければ助かります。
記事No.75306 のレス /過去ログ127より / 関連記事表示
削除チェック/

■75334  Re[7]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ 魔界の仮面弁士 -(2015/03/16(Mon) 17:22:24)
記事No.75306 のレス /過去ログ127より / 関連記事表示
削除チェック/

■75371  Re[6]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ 魔界の仮面弁士 -(2015/03/19(Thu) 11:50:26)
    No75321 (魔界の仮面弁士) に追記
    > MarshalAs 指定は必要になるだろうということで、SafeArray 指定で
    >  ・SafeArray
    >  ・SafeArray, SafeArraySubType:=VT_USERDEFINED
    >  ・SafeArray, SafeArraySubType:=VT_RECORD, SafeArrayUserDefinedSubType:=GetType(Structure1)
    > などを試してみましたが、HRESULT が E_INVALIDARG(0x80070057) を返すばかり。

    焦って試行錯誤してるけど、理論武装無しで闇雲に試しても駄目だよなぁ…。


    そもそも構造体のセーフ配列について知識が全然無いので、
    VB6 当時のマーシャリングがどうなっているかを調査してみるかな。


    まずは VB6 の VarType 関数を使って、バリアントの内部型を確認。

    ユーザー定義型に対して VarType を使うためには、その型を
    パブリックオブジェクトモジュールで公開しておく必要があるので、
    今回は ActiveX EXE プロジェクトにてテスト。

    '=== クラス モジュール(Instacing を「1:Private」以外に設定) ===
    Option Explicit
    ' No75314 のユーザー定義型
    Public Type Type1
     Long1 As Long
     Long2 As Long
     Long3 As Long
    End Type

    '=== 標準モジュール ===
    Option Explicit
    Public oType(0 To 9) As Type1
    Private Sub Main()
     Debug.Print Hex(VarType(oType))
     Debug.Print TypeName(oType)
    End Sub


    結果は、VarType = &H2024、TypeName = "Type1()" 。

    &H2024 は、「vbArray Or vbUserDefinedType」のことなので、
    VC++ 側の表現で言えば、「VT_ARRAY | VT_RECORD」相当だと分かる。



    念のため、SafeArrayGetVartype API でも調べてみる。

     Declare Function SafeArrayGetVartypeVB Lib "oleaut32" Alias "SafeArrayGetVartype" _
      (oType() As Any, pvt As VBA.VbVarType) As Long

     Declare Function SafeArrayGetVartypeOLE Lib "oleaut32" Alias "SafeArrayGetVartype" _
      (oType() As Any, pvt As olelib.VARENUM) As olelib.HRESULTS

    やはり、vbUserDefinedType = VT_RECORD = &H0024 が返されてきた。


    ということは、.NET 側のマーシャリングでは、
     <MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VarEnum.VT_RECORD)>
    を指定すれば良さそうだ、ということまで理解。

    でもまだうまく呼べない。次の手を考えないと。
記事No.75306 のレス /過去ログ127より / 関連記事表示
削除チェック/

■75372  Re[7]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ 魔界の仮面弁士 -(2015/03/19(Thu) 11:53:45)
    No75371 (魔界の仮面弁士) に追記
    > ということは、.NET 側のマーシャリングでは、
    >  <MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VarEnum.VT_RECORD)>
    > を指定すれば良さそうだ、ということまで理解。
    > でもまだうまく呼べない。次の手を考えないと。

    チラ裏投稿の続き。


    この段階で、VB.NET 側の実装はこのように書いている。

     Declare Function Test1 Lib "TestFunc.dll" _
      (<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VarEnum.VT_RECORD)> _
      ByRef Type1() As Structure1) As Integer

     Public Structure Structure1
      Dim Long1 As Integer
      Dim Long2 As Integer
      Dim Long3 As Integer
     End Structure

    結果は、『パラメーターが間違っています。』な E_INVALIDARG(0x80070057) の例外。


    …あぁ、そういえば構造体を COM 公開していなかった。

    <ComVisible(True), Guid("8D60602D-452A-48A1-ACEF-AF148A6E41B8")> _
    Public Structure Structure1
     Dim Long1 As Integer
     Dim Long2 As Integer
     Dim Long3 As Integer
    End Structure


    まだ駄目か。 No75336 に書いたとおり、RegAsm もしておこう。
    「RegAsm ConsoleApplication1.exe」…っと。

    --------------------
      RegAsm : warning RA0000 : 型は何も登録されませんでした。
    --------------------

    あれ?なんか忘れてるっけ?

    わかった、構造体を「Module Module1」の中で宣言しているからだ。
    「Public Module Module1」にしないと意味が無いわな。


    Module のスコープを Public に直して再実行。

     Dim iRet As Integer = -1
     For n = 0 To 9
      oType(n).Long1 = n * 100 + 1
      oType(n).Long2 = n * 100 + 2
      oType(n).Long3 = n * 100 + 3
     Next
     iRet = Test1(oType)

    おぉ、エラーなく呼べた!!
    配列が 10 件→1 件になる現象も起きていない!


    …いや、ちょっと待てよ。そういえば、Public Module 化した後、RegAsm 呼んでなかったな。
    もしかして COM 公開って意味が無いのだろうか。

    確認のため、COM 公開を止めてみよう。
     <ComVisible(False)> _
     Public Structure Structure1
      Dim Long1 As Integer
      Dim Long2 As Integer
      Dim Long3 As Integer
     End Structure

    ……うん。やっぱりコレだと E_INVALIDARG(0x80070057) の例外が発生する。
    ComVisible は必要っぽいな。RegAsm や TlbExp はしなくても大丈夫そう。


    呼び出しまではできるようになったので、次は、DLL からの情報を受け取れるかどうかの確認だな。
記事No.75306 のレス /過去ログ127より / 関連記事表示
削除チェック/

■75377  Re[8]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ 魔界の仮面弁士 -(2015/03/19(Thu) 12:09:19)
    No75372 (魔界の仮面弁士) に追記
    > iRet = Test1(oType)
    > おぉ、エラーなく呼べた!!
    > 呼び出しまではできるようになったので、次は、DLL からの情報を受け取れるかどうかの確認だな。


    今のところ、iRet の値は &H0024。これは DLL 側の実装を
     LPSAFEARRAY psa = *Type1;
     VARTYPE vt;
     SafeArrayGetVartype(psa, &vt);
     return vt;
    にしているからなので、内容的には正しそう。(&H0024 は 定数 VT_RECORD と同じ値)


    でも、DLL 側で値を編集するのってどうやるんだろう。
    C++ は全然知らない上に、SAFEARRAY の API にも詳しくないんだよなぁ。

    とりあえず、見様見真似で書いてみよう。


     LPSAFEARRAY psa = *Type1;
     
     long lb, ub;
     SafeArrayLock(psa);
     SafeArrayGetLBound(psa, 1, &lb); // lb = LBound(Type1, 1)
     SafeArrayGetUBound(psa, 1, &ub); // ub = UBound(Type1, 2)
     SafeArrayUnlock(psa);
     
     Structure1 *p = NULL;
     SafeArrayAccessData(psa, (void**)&p);
     for(long idx = lb; idx <= ub; idx++)
     {
      p[idx].Long1 += 70;
      p[idx].Long2 += 80;
      p[idx].Long3 += 90;
     }
     SafeArrayUnaccessData(psa);
     return ub - lb + 1; // 要素数



    C++ は苦手というか勉強したことが無い(C が少し読める程度)ので、
    これで正しいのかどうかは全然自信が無いけど、一応コンパイルは通ったようだ。

    エラーチェックの処理とか入れてないのが不安だけど、
    とりあえず VB6 から呼んでみよう。

     For n = 0 To 9
      oType(n).Long1 = n * 100 + 1
      oType(n).Long2 = n * 100 + 2
      oType(n).Long3 = n * 100 + 3
     Next
     iRet = Test1(oType)

    よしよし、oType(2) が { 201, 202, 203 } → { 271, 282, 293 } に書き換わっているな。

    次は、VB.NET で呼んでみると…こっちも大丈夫そうだ!

    ってことで完成形のお披露目ー★

    Imports System.Runtime.InteropServices
    Public Module Module1
     <ComVisible(True), Guid("8D60602D-452A-48A1-ACEF-AF148A6E41B8")> _
     Public Structure Structure1
      Dim Long1 As Integer
      Dim Long2 As Integer
      Dim Long3 As Integer
     End Structure

     Declare Function Test1 Lib "TestFunc.dll" _
      (<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VarEnum.VT_RECORD)> ByRef oStructure() As Structure1) As Integer

     Public oType(9) As Structure1
     Sub Main()
      Dim iRet As Integer = -1
      For n = 0 To 9
       oType(n).Long1 = n * 100 + 1
       oType(n).Long2 = n * 100 + 2
       oType(n).Long3 = n * 100 + 3
      Next
      iRet = Test1(oType)
      
     End Sub

    End Module
記事No.75306 のレス /過去ログ127より / 関連記事表示
削除チェック/

■75392  Re[9]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ とら -(2015/03/19(Thu) 19:01:17)
    No75377 (魔界の仮面弁士 さん) に返信
    
    一括表示で2ページ目になっていたため気付くのが遅れました、すみません!
    
    こちらでも同じようにやってみたのですが、タイプライブラリの生成に失敗しましたといったエラーが発生してしまいました。
    
    
    >  LPSAFEARRAY psa = *Type1;
    
    今回成功したパターンは、VC++で受け取った後にLPSAFEARRAY型に代入しているという事は
    
        TEST_API int __stdcall Test1(LPSAFEARRAY *Type1)
    
    という元々の状態ではなく
    
        TEST_API int __stdcall Test1(T_Struct *type1)
    
    の状態で受け取っているという事でしょうか?
    
    
    
    > C++ は苦手というか勉強したことが無い(C が少し読める程度)ので、
    > これで正しいのかどうかは全然自信が無いけど、一応コンパイルは通ったようだ。
    わざわざあれこれ挑戦して頂いたようで大変恐縮です、有難う御座います。
    
    
    
    >(1) AssemblyInfo.vb にて、
    >   <Assembly: ComVisible(True)>
    >   <Assembly: Guid("……")>
    >  を指定しておきます。プロジェクトのプロパティの[アプリケーション]-[アセンブリ情報]でも指定可。
    
    >  <ComVisible(True), Guid("8D60602D-452A-48A1-ACEF-AF148A6E41B8")> _
    
    GUIDの部分が少々理解が追い付きませんでしたが、ここに設定する値は
    
    >Guid.NewGuid().ToString("D")等で生成した値を指定
    
    とありましたが、この値はこの関数を実行するたびに変化するのでしょうか
    
    
    また、
    
    >(2) 構造体側にも、また別の GUID を割り当てておきます。
    
    とありましたが、AssemblyInfo.vbに設定するGUIDと構造体に設定するGUIDは違うものにしておくのですか?
    
    
    
    そちらでは結果が出ている事が確認できているところすみませんが、何卒よろしくお願い致します。
    
記事No.75306 のレス /過去ログ127より / 関連記事表示
削除チェック/

■75394  Re[10]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ 魔界の仮面弁士 -(2015/03/19(Thu) 20:05:29)
    No75392 (とら さん) に返信
    > 一括表示で2ページ目になっていたため気付くのが遅れました、すみません!
    > こちらでも同じようにやってみたのですが、タイプライブラリの生成に失敗しましたといったエラーが発生してしまいました。

    型公開は必要ですが、タイプライブラリを明示的に作る必要は無さそうです。

    もし、ComVisible を True にしても駄目なようならば、VS を管理者起動してみてください。
    レジストリ登録のためには管理者権限が必要なので。


    >> LPSAFEARRAY psa = *Type1;
    > 今回成功したパターンは、VC++で受け取った後にLPSAFEARRAY型に代入しているという事は
    いえ、説明文では C++ 側の関数定義を書いていなかったので、
    それが分かるにしただけです。引数自体は LPSAFEARRAY *Type1 のままですね。


    >> <ComVisible(True), Guid("8D60602D-452A-48A1-ACEF-AF148A6E41B8")> _
    > GUIDの部分が少々理解が追い付きませんでしたが、
    GUID は、『ネットワーク上で必ず一意であることが保障される128ビットの数値』です。

    ここでは、「クラス」「インターフェイス」「タイプライブラリ」などといった
    それぞれの COM オブジェクトに付けられた 128bit の識別番号だと思ってください。


    たとえば、ActiveX Data Object のタイプライブリには 00000205-0000-0010-8000-00AA006D2EA4 という
    GUID 値(LIBID) が割り当てられていますし、Excel の Application オブジェクトであれば、
    00024500-0000-0000-C000-000000000046 という GUID値(CLSID)が割り当てられているといった具合に。


    今回は、自作したデータ型なので、既存のGUID値ではなく、新規に用意した GUID 値を割り当てることになります。
    もし、構造体が複数あるのなら、それぞれに違う GUID を用意してください。Assmbly 側も然り。



    >> Guid.NewGuid().ToString("D")等で生成した値を指定
    > とありましたが、この値はこの関数を実行するたびに変化するのでしょうか
    はい。生成するたびに変わります。そして、同じ値は二度と生成されません。
    「重複しないランダムな値」を生成するものだと思ってください。


    > >(2) 構造体側にも、また別の GUID を割り当てておきます。
    > とありましたが、AssemblyInfo.vbに設定するGUIDと構造体に設定するGUIDは違うものにしておくのですか?
    重複する GUID 値を指定してはいけません。
    すべて別の値を使用する必要があります。

    複数の箇所で同じ GUID 値を使うことがあるとすれば、たとえば
    A.DLL と B.DLL と C.EXE が「同じ構造体」を再定義する場合などです。

    もっとも、そういう場合は、共有用のタイプライブラリを用意して、
    それを各プロジェクトで参照設定した方が分かりやすいですけれどね。
記事No.75306 のレス /過去ログ127より / 関連記事表示
削除チェック/

■75398  VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ とら -(2015/03/20(Fri) 13:33:23)
    2015/03/20(Fri) 13:35:06 編集(投稿者)

    No75394 (魔界の仮面弁士 さん) に返信

    > 型公開は必要ですが、タイプライブラリを明示的に作る必要は無さそうです。
    >
    > もし、ComVisible を True にしても駄目なようならば、VS を管理者起動してみてください。
    > レジストリ登録のためには管理者権限が必要なので。

    前回ご提示頂いた手法にて正常に構造体配列の受け渡しが可能な事を確認致しました。


    自身の認識確認、及び今後参考にされる方が解り易いように手順をまとめ直させて頂きますと、

    @ GUIDを2つ生成してメモする
      ・VS付属の「GUIDGEN.EXE」 や デバッグにて 「Guid.NewGuid().ToString("D")」等を実行する

    A AssemblyInfo.vb に 下記2つを追記する。
      ・<Assembly: ComVisible(True)>
      ・<Assembly: Guid("【@で取得したGUIDのうち1つ】")>

    B 構造体を宣言しているモジュールを Public にする

    C 構造体を宣言しているモジュールにて下記をインポートする
      ・System.Runtime.InteropServices

    D 構造体の宣言部分上部に下記を追記しCOM公開する
      ・<ComVisible(True), Guid("【@で取得したGUIDのうち1つ(Aで使用していないもの)】")> _

      例:
       <ComVisible(True), Guid("8D60602D-452A-48A1-ACEF-AF148A6E41B8")> _  
       Public Structure Structure1
        Dim Long1 As Integer
        Dim Long2 As Integer
        Dim Long3 As Integer
       End Structure

    E Declareの引数指定部分に下記マーシャリングを追記
      ・<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VarEnum.VT_RECORD)>

      例:
        Declare Function Test1 Lib "TestFunc.dll" _
        (<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VarEnum.VT_RECORD)> ByRef oStructure() As Structure1) As Integer

    F 後は従来通りにVC++DLLを呼び出す



    > GUID は、『ネットワーク上で必ず一意であることが保障される128ビットの数値』です。

    他で生成されたGUIDと一致する確率が1/2^61とかなんとか、天文学的数字ってやつですね。
    Globally (世界的に) Unique (固有の) Identifier (識別子)ってまんまの意味の略語だったのか。


    > 今回は、自作したデータ型なので、既存のGUID値ではなく、新規に用意した GUID 値を割り当てることになります。
    > もし、構造体が複数あるのなら、それぞれに違う GUID を用意してください。Assmbly 側も然り。

    つまり1つの構造体配列をやり取りするのに2つのGUIDを生成する必要があるが、

    > 複数の箇所で同じ GUID 値を使うことがあるとすれば、たとえば
    > A.DLL と B.DLL と C.EXE が「同じ構造体」を再定義する場合などです。

    同じ構造体であれば別の個所で使用する分には新たに別のGUIDを生成する必要はないが、

    > もっとも、そういう場合は、共有用のタイプライブラリを用意して、
    > それを各プロジェクトで参照設定した方が分かりやすいですけれどね。

    確かにごもっともです。



    以上、大変お世話になりました。
記事No.75306 のレス / END /過去ログ127より / 関連記事表示
削除チェック/

次の20件>

<< 0 | 1 >>

パスワード/

- Child Tree -