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

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

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

VB(ビジュアルベーシック)はマイクロソフトによってつくられたオブジェクト指向プログラミング言語のひとつで、同社のQuickBASICが拡張されたものです。VB6の進化版といわれています。

Visual Studio 2013

Microsoft Visual Studio 2013は、Microsoftによる統合開発環境(IDE)であり、多種多様なプログラミング言語に対応しています。 Visual Studio 2012の次のバージョンです

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

Q&A

解決済

3回答

10510閲覧

VBのFindWindow関数を繰り返すたびに第2引数の文字列が削れて減っていく

ot2os

総合スコア23

VB

VB(ビジュアルベーシック)はマイクロソフトによってつくられたオブジェクト指向プログラミング言語のひとつで、同社のQuickBASICが拡張されたものです。VB6の進化版といわれています。

Visual Studio 2013

Microsoft Visual Studio 2013は、Microsoftによる統合開発環境(IDE)であり、多種多様なプログラミング言語に対応しています。 Visual Studio 2012の次のバージョンです

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

0グッド

0クリップ

投稿2017/07/24 00:28

編集2017/07/24 07:26

自動で[プリンターのプロパティ]を呼び出し、[ノズルチェックパターン印刷]を実施するプログラムをVBで制作したいと思います。

途中、FindWindow関数実施時、2番目の引数(ウィンドウ名)の値が実施するたびに勝手に減っていきます。
ましてByVal参照なのに勝手に引数の値が変わる理由がわからず、アドバイスをお願いいたします。

ちなみに、プログラムを実行すると[プリンターのプロパティ]ウィンドウまでは出ます。
手動でのマウス操作は正常にタブ操作、ボタン操作できます。

●ソースコード(Form1.vb):Form1にはButton1のみ配置

VB.net

1Public Class Form1 2 3 Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _ 4 (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer 5 6 Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" _ 7 (ByVal hwndParent As Integer, ByVal hwndChildAfter As Integer, _ 8 ByVal lpszClass As String, ByVal lpszWindow As String) As Integer 9 10 11 'SendMessage用 12 Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _ 13 (ByVal hWnd As Integer, ByVal MSG As Integer, _ 14 ByVal wParam As Integer, ByVal lParam As Integer) As Integer 15 16 17 Public Const BM_CLICK = &HF5 18 Public Const CB_SETCURSEL = &H14E& 19 20 Public Const WM_LBUTTONDOWN = &H201 21 Public Const WM_LBUTTONUP = &H202 22 23 Const MK_LBUTTON = &H1 24 25 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 26 Dim Printer_Name As String = "【ダミー】Canon Inkjet MP630 series" 27 28 'Processオブジェクトを作成 29 Dim p As New System.Diagnostics.Process() 30 31 'ComSpec(cmd.exe)のパスを取得して、FileNameプロパティに指定 32 p.StartInfo.FileName = System.Environment.GetEnvironmentVariable("ComSpec") 33 34 'ウィンドウを表示しないようにする 35 p.StartInfo.CreateNoWindow = True 36 'コマンドラインを指定("/c"は実行後閉じるために必要) 37 p.StartInfo.Arguments = "/c start rundll32 printui.dll, PrintUIEntry /e /n """ & Printer_Name & """" 38 39 '起動 40 p.Start() 41 42 'プロセス終了まで待機する 43 'WaitForExitはReadToEndの後である必要がある 44 '(親プロセス、子プロセスでブロック防止のため) 45 p.WaitForExit() 46 p.Close() 47 48 49 Dim hwnd1 As Integer 50 51 'Text: 【ダミー】Canon Inkjet MP630 series 印刷設定 52 hwnd1 = FW("#32770", Printer_Name & " 印刷設定") 53 Call FWex(hwnd1, 0, "SysTabControl32", "") 54 55 'とりあえずここまで、この後、タブ切り替え、ボタン操作にてノズルチェックパターン印刷を実施 56 57 End Sub 58 59 Private Function FW(ByVal Class_Name As String, ByVal Window_Name As String) 60 Dim hwnd As Integer = 0 61 Do Until hwnd > 0 62 Debug.Print("Window_Name:" & Window_Name) '←●今回のImmidiate Window出力 63 hwnd = FindWindow(Class_Name, Window_Name) 64 System.Threading.Thread.Sleep(200) '念のため0.2秒停止 65 My.Application.DoEvents() '描画フリーズ防止 66 Loop 67 FW = hwnd 68 Debug.Print(Window_Name & ":" & hwnd) 69 End Function 70 71 Private Function FWex(ByVal hwnd1 As Integer, ByVal Arg As Integer, ByVal Class_Name As String, ByVal Obj_Name As String) 72 Dim hwnd2 As Integer = 0 73 Do Until hwnd2 > 0 74 hwnd2 = FindWindowEx(hwnd1, 0, Class_Name, Obj_Name) 75 System.Threading.Thread.Sleep(200) '念のため0.2秒停止 76 My.Application.DoEvents() '描画フリーズ防止 77 Loop 78 FWex = hwnd2 79 Debug.Print(Obj_Name & "、" & Class_Name & ":" & hwnd2) 80 End Function 81 82End Class

●Immediate Window の出力
#######
Window_Name:【ダミー】Canon Inkjet MP630 series 印刷設定
Window_Name:【ダミー】Canon Inkjet MP630 series
Window_Name:【ダミー】Canon Inkjet MP630 s
Window_Name:【ダミー】Canon Inkjet MP
Window_Name:【ダミー】Canon Inkj
Window_Name:【ダミー】Canon
Window_Name:【ダミー】
Window_Name:【ダ・
Window_Name:【・
Window_Name:【
Window_Name:・
Window_Name:・
Window_Name:・
Window_Name:・
#######

ちなみに、FindWindowの処理をFunction内ではなく、Private Sub Button1_Clickのまま実施すると、引数の値は変化せず、正常に該当hwndがヒットして処理が進みます。

VB.net

1 'hwnd1 = FW("#32770", Printer_Name & " 印刷設定") 2 Do Until hwnd1 > 0 3 Debug.Print("Window_Name:" & Printer_Name & " 印刷設定") 4 hwnd1 = FindWindow("#32770", Printer_Name & " 印刷設定") 5 System.Threading.Thread.Sleep(200) '念のため0.2秒停止 6 My.Application.DoEvents() '描画フリーズ防止 7 Loop

開発環境:
OS:Windows10x86 1703
Visual Studio 2013

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

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

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

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

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

guest

回答3

0

この現象は、.net frameworkの不具合だと思います。

まず、Visual Basic.NetでのDeclare文のString型のByValとByRefは、値渡し、参照渡しという意味ではありません。
String型をどういう形式に変換して、DLLに渡すかという指示になります。

ByValで渡しても、DLL側で文字列を変更すると、その結果はVB側に反映されます。

今回の現象では、VB側のUnicode文字列を、マルチバイト文字列に変更する際に、文字列の長さの計算法に不具合があり、このような結果になっていると思います。

なぜ、Functionに処理を切り出すと、不具合が発生するかは不明ですが、何らかのメモリ破壊を起こしているためと、思われます。

不具合を解消するためには、Declare文を以下のように変更するのが良いのではないでしょうか。

Visual

1<DllImport("user32.dll", CharSet:=CharSet.Unicode)> 2 Private Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As Integer 3 End Function

この場合、DLLの関数としては、FindWindowWが呼ばれますが、CharSet.AnsiとするとFindWindowAが呼ばれます。どちらでも、動作に違いはありません。

投稿2017/07/25 02:39

Harahira

総合スコア243

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

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

ot2os

2017/07/25 05:55

こちらもうまくいきました! お約束通り、Public Class Form1 の前の行に`Imports System.Runtime.InteropServices `を宣言していただいたコードをDeclareの代わりに記載で行けました! それにしても、 .net の不具合なんですね。 不具合発生の仕組みまで教えていただいてありがとうございます。
guest

0

Declare Function での文字コード変換がうまくいっていない気がします。
Declare Function → Declare Auto Function としてみてはどうでしょうか?

投稿2017/07/24 06:19

koguma98

総合スコア288

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

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

ot2os

2017/07/24 07:18

ありがとうございます。 `Declare Auto Function`にしたところ、引数の値は勝手に変わらず、Debug.Printの結果は下記のまま繰り返しになりました。 > Window_Name:【ダミー】Canon Inkjet MP630 series 印刷設定 しかし、上記を繰り返すのみで、一向にhwndの値が変わりません。 文字コードの問題ですかね。 ちなみに、Function内で処理せずに、直接元の`Private Sub Button1_Click`内で同様の処理をすると、`Declare Function`でも正常に該当hwndがヒットして処理が進みました。
guest

0

ベストアンサー

Alias "FindWindowA" としていますが、Windows 10では FindWindowW を使うと良いでしょう。
現在Windows内部ではUnicodeが使われており、Unicodeを利用する場合末尾がAではなくWのAPIを利用します。

投稿2017/07/24 16:19

koguma98

総合スコア288

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

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

ot2os

2017/07/25 05:35

ありがとうございます! FindWindowの宣言時に下記のようにAliasを "FindWindowW" 、Declare の後に Unicode を明記したところ、正常に動作しました! ```VB.net Declare Unicode Function FindWindow Lib "user32.dll" Alias "FindWindowW" _ (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer ```
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問