VB.netでのwin32api呼び出し

このQ&Aのポイント
  • VB.netでwin32apiを呼び出し、正しくデータをセットできない問題について
  • vb.netで機器との通信を行うためwinapi32で作られたドライバdllをインポートしたが、受信データが正常に受け取れない。
  • VB6.0のプログラムをvb.netに移植し、win32apiを使用して通信を行っているが、受信データの取得に問題がある。お助けください。
回答を見る
  • ベストアンサー

VB.netでのwin32api呼び出し

VB.netでwin32apiを呼び出したが変数にデータが正しくセットされない vb6.0のプログラムをvb.netに移植作業しています。 vb.netで機器との通信を行うためwinapi32で作られたドライバdllをインポートしたのですが受信データが正常に受け取れません。もう1週間も悩み続けています。 詳しい方お助けください。 //win32api側// DWORD Receive(HANDLE handle,PBYTE pbReceiveBuffer,WORD wBufferLength, _ PWORD pwReceiveLength,PDWORD pdwErrCode); //VB側// <DllImport("Des_DLL", CharSet:=CharSet.Auto)> _ Public Function Receive(ByVal hPath As Intptr, ByRef ReceiveBuffer As IntPtr, _ ByVal ReceiveBuffLength As Ushort ByRef ReceiveLength As Ushort, _ ByRef lErrCode As Uint) As Uint End Function Dim rd_buf(1018) As Byte Dim rbf_l As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(rd_buf)) 'アンマネージメモリ 確保 Marshal.Copy(rbf_l, rd_buf, 0, rd_buf.Length) 'アンマネージメモリからマネージメモリにコピー ret = Receive(Path, rbf_l, rdbuffer_length, rd_length, ErrCode) Call des_datawrite(rd_buf, rd_length, 2) ' 受信データの書き込み For i = 0 To rd_length - 1 ' 受信データセット DES.rd_buf(DES.rd_cnt) = rd_buf(i) DES.rd_cnt = DES.rd_cnt + 1 Next i DesRD_Normal = True Marshal.FreeCoTaskMem(rbf_l) End Function Receive()は機器からの情報吸い上げレスポンス関数です。 Public Sub des_datawrite(ByVal wt_data() As Byte, ByVal length As Integer, ByVal Mode As Integer) Dim free_num As Integer Dim i As Integer Dim cv_buf As String cv_buf = "" For i = 0 To length - 1 cv_buf = cv_buf & Microsoft.VisualBasic.Right("00" & Hex(wt_data(i)), 2) & " " Next i free_num = FreeFile() FileOpen(free_num, GetAppPath() & DES_DATA, OpenMode.Append) If Mode = 1 Then Print(free_num, "[<-sd(" & DateTime.Now.ToString("yyyyMMddHHmm") & ")]" & Mid (cv_buf, 1, Len(cv_buf) - 1)) ElseIf Mode = 2 Then ElseIf Mode = 2 Then Print(free_num, "[->rd(" & DateTime.Now.ToString("yyyyMMddHHmm") & ")]" & Mid(cv_buf, 1, Len(cv_buf) - 1)) End If FileClose(free_num) End Sub

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

「正しくセットされない」ということですが、正しくセットされる/されない以前に、正しく実行できないのではないですか? C 側が PBYTE pbReceiveBuffer となっているのに、VB 側の Recieve の宣言が ByRef ReceiveBuffer As IntPtr となっていると、rbf_l に格納されている値(つまり、Marshal.AllocHGlobal で確保したメモリのアドレス ) を渡したいのに、rbf_1 自身のアドレスを渡してしまいます。 rbuf_1 って、ポインタですから、32 bit 環境なら 4 バイトしかないワケで、4バイトしか確保されていないところに1018 byte ものデータを書き込もうとするとメモリアクセス違反が起きるはずです。 ByVal ReceiveBuffer As IntPtr にしてみてください。 あと、たぶん、Marshal.Copy と Recieve の順番が逆ですね。 それか、Marshal.AllocHGlobal、Marshal.Copy とかは使用せずに、 <DllImport("D:\Nobuyuki\Projects\Test\VcDllTest\Debug\VcDllTest.dll", CharSet:=CharSet.Auto)> _ Public Function Receive(ByVal hPath As IntPtr, ByVal ReceiveBuffer() As Byte, ByVal ReceiveBuffLength As UShort, ByRef ReceiveLength As UShort, ByRef lErrCode As UInt32) As UInt32 End Function と宣言しておいて、 Dim ret As Integer = Receive(Path, rd_buf, rd_buf.Length, rd_length, ErrCode) とするのがシンプルで良いような気もします。

ikaruga817
質問者

お礼

ありがとうございます。まさにその通りでした。 まだ.netの事があまり分かって無く勉強する日々です 今回は勉強になりました。

その他の回答 (1)

回答No.2

一つ前の回答の <DllImport・・・ のところは、そちらの環境に合わせてくださいね。 (こちらの環境の内容のまま載せてしまいました・・・。(^^; 一度書き込みしちゃうと修正できないんですよね・・・)

関連するQ&A

  • VB.NETで、配列をテーブルに変換する。

    VB.NETで、一次元配列string()にあるデータを、DataTableに変換 したいのですが、「型'String'の値を'System,Data,DataTable'に変換できません。」 と、エラーが発生してしまいます。 s1に、配列データが入っています。 Dim dt As DataTable Dim cnt As Integer Dim i As Integer dt = New DataTable count = s1.Length For i = 0 To cnt - 1 dt = CType(s1(i), DataTable) Next 解決方法が見つからず、行き詰っております。 宜しくお願い致します。

  • VB.NETで値や参照について ByRefなど

    VB.NETで値や参照について、まだ初学ですがよろしくお願いします。 VBは2008です。 以下のようなs文字列を参照引数にしたSetDataメソッドがあります。 ByRef s As Stringという引数は、SetData内でsを書き換えると、 呼び出したSetDataメソッド外でも中身が変わるので 私のByRefの認識ではポインタと解釈しています。間違っているでしょうか? SetData(1,1, buf)とすれば、DataGridViewの中は、「初期値」という文字が表示されます。 別のメソッド(KaKikae)でbufを"あ"という文字に変えた場合、SetDataメソッドを使わなくても 書き換わっていると思っていたのですが、実際実行してみると書き換わりません。 値や参照について理解が足りないからだと思いますがわかりません。 どのようにすれば、それが実現できるのでしょうか? Public Class HogeClass Private buf As String = "初期値" Private Sub SetData(ByVal x As Integer, ByVal y As Integer, ByRef s As String) As Boolean Dim dg As DataGridView dg = DataGridView1 dg.Item(x, y).value = s End Sub Private Sub KaKikae() buf = "あ" End Sub End Class

  • VB6.0 テキストデータの受け取り

    VB初心者です。 VB6.0を使用しています。 Agilentのスペアナからのトレースデータをテキストで、"RecvData1"という文字列に受け取らせたいと考えています。 下記のように記述したのですが、RecvData1にテキストデータをうまく受け渡すことができません。 どこを改善すればよろしいでしょうか。 Dim RecvData1 As String stats = viVPrintf(vi, "TRAC:DATA? TRACE1" + Chr$(10), 0) stats = viVScanf(vi, RecvData1, 0) viVScanfの定義 ↓ Public Declare Function viVScanf Lib "VISA32.DLL" Alias "#272" (ByVal vi As Long, ByVal readFmt As String, params As Any) As Long なお、「stats = viVPrintf(vi, "TRAC:DATA? TRACE1" + Chr$(10), 0)」の部分のコマンドが測定機に正しく送られていることは確認済みです。 やりたいことをVisa Assistantを使用して行った場合のC言語の記述と結果 ↓ -------------------------------------------------------------------- viPrintf(vi,"TRAC:DATA? TRACE1\n"); char buf[32768]; int bufLength = sizeof(buf); ViScanf(vi,"%#t", &bufLength, buf); buf[] = {"-28.986280,-30.730440,-44.042957,-68.885155,-80.233..... bufLength = 5071; --------------------------------------------------------------------

  • VB6のTYPE文をVB.NETのStructureに変えるとき

    VB6のTYPE文をVB.NETのStructureに変えるとき 下記VB6のコードをVB.NETのStructureに変える場合 Type kouzou1 i As Integer j As Integer a As String * 20 b As String * 50 End Type を下記にしてみたのですが *20,*50のところは、どのように表現するのでしょうか。 Structure kouzou1 Dim i As Integer Dim j As Integer Dim a As String * 20 <- ステートメントの終わりを示してくださいのエラーになる。 Dim b As String * 50 <- ステートメントの終わりを示してくださいのエラーになる。 End Structure お教え下さい。

  • VB .NetのDLL参照について

    名前付パイプの処理をしているのですが、DLLが参照できません。 Public Class ClsJi01   Public Declare Function MakePipe Lib "\DLL\Point.DLL" (ByVal pipe_name As String, ByVal buf_size As Integer, ByVal max_instances As Short, ByVal hpipe As Integer, ByVal err_code As Integer) As Integer  Public Sub M_Pipe()   Dim r As Integer   Dim rpipe As Integer   Dim err_code As Integer   r = MakePipe("\\.\pipe\RS04", 255, 16, rpipe, err_code)  End Sub End Class Point.DLLは以前VB6.0の時に使用していたDLLで自作です。 これで実行すると「オブジェクト参照がオブジェクト インスタンスに設定されていません。」と出ます。 どうしたら良いのでしょうか?

  • VB.NETでのデータベース書き込みについて

    リストレビューに表示されているデータをデータベースに書き込む処理を追加したいのですが、データセットにメモリ上のテーブルを作成してデータベースへ書き込む方が良いのでしょうか? それとも直接データベースに書き込む方が良いのでしょうか? 前者のテーブル作成のコードは書きの通りです。 Public Function AddDataSetTable(ByVal kojo_cd() As String, ByVal kojo_name() As String, ByVal kojo_date() As String)   Dim dtSet As New DataSet("DataSetTable")   Dim dtTable As New DataTable("CalDatTable")   Dim fmain As New FrmMain   Dim i As Integer   'テーブルに列を追加    With dtTable.Columns     .Add("コード")     .Add("名称")     .Add("日にち")    End With   'テーブルに行を追加   With dtTable.Rows    For i = 0 To UBound(kojo_cd)     .Add(New Object() {kojo_cd(i), kojo_name(i), kojo_date(i)})    Next i   End With   'データセットにテーブルを追加   dtSet.Tables.Add(dtTable) End Function

  • VB2005 から DLL を呼び出す

    VB 初心者です。 今、VB の練習ということで VB 2005 Express Edition を使って、個人用ブラウザをつくっています。Web ページの表示は Webbrowser コンポーネントを使っています。 その仕様で、閲覧先によって HTTP Proxy を変更するようになっています。(自分で決めたんですが) いろいろ調べてみると、urlmon.dll の UrlMkSetSessionOption() を呼べば自分のアプリケーション限定で Proxy を変更できるようだ、ということがわかりました。 古い VB など(VB 6 とか?)では、 Private Declare Sub UrlMkSetSessionOption Lib "urlmon.dll" _ (ByVal dwOption As Long, ByVal pBuffer As Any, _ ByVal dwBufferLength As Long, _ ByVal dwReserved As Long) このような感じで宣言するとかあったんですが、VB2005 では Any がダメだとか、 Type INTERNET_PROXY_INFO Dim dwAccessType As Long Dim lpszProxy As String Dim lpszProxyBypass As String End Type で Type はダメだとか、呼び出し側で、LenB を使おうとしたら使えないだとか、INTERNET_OPTION_PROXY の値がわからないなど、問題が山積みです。 上記 DLL を VB 2005 で使ったことがある人がいたら(またはわかる人)、使い方を教えてもらえないでしょうか?

  • VB.netでパスワード変更

    下記のようなパスワードを変更するフォームをVB.netで作成したのですが、 実行すると、いつも異なるretValの値がかえってきて変更できません。 retValの値もよくわからない大きな数値がかえってくるのでどのようなエラーかも 判断つかず。 どこが間違っているかお分かりになる方いらっしゃいますでしょうか。 Public Class Form1 Private Declare Function NetUserChangePassword Lib "netapi32.dll" (ByVal Domain As String, ByVal User As String, ByVal OldPass As String, ByVal NewPass As String) As Long Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim retVal As Long Dim sDomain As String Dim sUser As String Dim sOldPass As String Dim sNewPass As String sDomain = "xxxxxxx" ←ここはサーバのIPアドレス sUser = TextBox1.Text sOldPass = TextBox2.Text sNewPass = TextBox3.Text retVal = NetUserChangePassword(sDomain, sUser, sOldPass, sNewPass) MsgBox(retVal) End Sub End Class

  • VB.NETのデリゲートについて

    VB.NETのデリゲートについて質問です。 以下のプログラムなのですが、 デリゲート型をインスタンス化しているところで、コンストラクタにパラメータを渡していますが、 そのコンストラクタはどこに定義されているのでしょうか。 (AddressOf t1.Ohayou)というパラメータが渡されていますが、このパラメータを受け取っているコンストラクタがどれなのかが分かりません。 ご教示よろしくお願いいたします。 Delegate Sub Myprint(ByVal s As String) Module Module1 Sub Main() Dim t1 As Test1 = New Test1() Dim t2 As TEst2 = New Test2() Dim d As Myprint = New Myprint(AddressOf t1.Ohayou) d.Invoke("VB太郎") d = New Myprint(AddressOf t2.Konbanwa) d.Invoke("VB太郎") End Sub End Module Class Test1 Sub Ohayou(ByVal s As String) Console.WriteLine("おはようございます。{0}です。", s) End Sub End Class Class Test2 Sub Konbanwa(ByVal s As String) Console.WriteLine("こんばんわ。{0}です。", s) End Sub End Class

  • このような使い方は間違っているのでしょうか?(VB.NET2002)

    このような使い方は間違っているのでしょうか?(VB.NET2002) Dim count As Int16 Private Sub JOB(ByVal x) x = x + 1 TextBox1.Text = x End Sub Private Sub Button1_Click(・・・・ JOB(count) End Sub

専門家に質問してみよう