既存のアプリケーションにあるコンポーネント「syslistview32」から文字列取得を取得したいのです。
自分なりに調べてみましたが、SendMessageを使用するのだと思いますが、具体的な記述(流れ)の方法をどうしていいのか分かりません。
解る方いましたら、ご教授ください。

このQ&Aに関連する最新のQ&A

A 回答 (1件)

>SendMessageを使用するのだと思いますが


SendMessageを利用するのであれば、共有メモリを利用します。

最初に
http://oshiete1.goo.ne.jp/kotaeru.php3?q=817941
の#2の参考URLを見てから#2の回答を見てください。
CをVB化しています。
(実を言うと、これ私が別のメーリングリストで公開したのに非常に似ているのですが^^;)
あとはLVM_GETITEMを確保した共有メモリ部に、書き込む処理を行っていきます。


共有メモリを利用するには、OS別の方法を考慮しなければならないのです。
SendMessage以外の別方法が手元にあるので、それを張ってきますね^^

デスクトップもsyslistview32でできてますので、それを捕らえる方法です。

要参照設定
oleacc.dll
(NT4ならばService Pack 6a)
(Win98ならば `ユーザ補助`をインストール)

んでもってサンプル
Option Explicit

Private Type UUID
  Data1 As Long
  Data2 As Integer
  Data3 As Integer
  Data4(7) As Byte
End Type

Private Const CHILDID_SELF = 0&
Private Const OBJID_CLIENT = &HFFFFFFFC

Private Declare Function AccessibleObjectFromWindow Lib "oleacc" _
  (ByVal hWnd As Long, _
  ByVal dwObjectID As Long, _
  ByRef riid As UUID, _
  ByRef ppvObject As Any) As Long

Private IID_IAccessible As UUID

Private Enum NVADIRConstants
  NAVDIR_MIN
  NAVDIR_UP
  NAVDIR_DOWN
  NAVDIR_LEFT
  NAVDIR_RIGHT
  NAVDIR_NEXT
  NAVDIR_PREVIOUS
  NAVDIR_FIRSTCHILD
  NAVDIR_LASTCHILD
  NAVDIR_MAX
End Enum

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWndParent As Long, ByVal hWndChildAfter As Long, ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Sub Main()
  Dim lngWnd As Long
  Dim colWk  As Collection
  Dim i    As Integer
  
  Call UUID_Init
  
  lngWnd = GetSysLVHwnd
  If Not GetListViewItems(lngWnd, colWk) Then
    MsgBox "失敗"
  End If
  
  For i = 1 To colWk.Count
    Debug.Print colWk(i)
  Next i
  
End Sub

Private Sub UUID_Init()
  With IID_IAccessible
    .Data1 = &H618736E0
    .Data2 = &H3C3D
    .Data3 = &H11CF
    .Data4(0) = &H81
    .Data4(1) = &HC
    .Data4(2) = &H0
    .Data4(3) = &HAA
    .Data4(4) = &H0
    .Data4(5) = &H38
    .Data4(6) = &H9B
    .Data4(7) = &H71
  End With
End Sub

Private Function GetSysLVHwnd() As Long
  Dim h As Long
  h = FindWindow("Progman", vbNullString)
  h = FindWindowEx(h, 0, "SHELLDLL_defVIEW", vbNullString)
  GetSysLVHwnd = FindWindowEx(h, 0, "SysListView32", vbNullString)
End Function

Private Function GetListViewItems(ByVal inWnd As Long, Optional otCol As Collection) As Boolean
  Dim objAcc   As IAccessible
  Dim varChild  As Variant
  
  Set otCol = Nothing

  Call AccessibleObjectFromWindow(inWnd, OBJID_CLIENT, IID_IAccessible, objAcc)

  If objAcc Is Nothing Then
    Exit Function
  End If
  
  Set otCol = New Collection
  
  varChild = objAcc.accNavigate(NAVDIR_FIRSTCHILD, CHILDID_SELF)
  Do Until IsEmpty(varChild)
    otCol.Add objAcc.accName(varChild)
    varChild = objAcc.accNavigate(NAVDIR_NEXT, varChild)
  Loop
  Set objAcc = Nothing
  GetListViewItems = True
End Function

参考URL:http://oshiete1.goo.ne.jp/kotaeru.php3?q=817941
    • good
    • 0
この回答へのお礼

ご親切な回答ありがとうございました。
勉強したいと思います。

お礼日時:2005/04/16 13:09

このQ&Aに関連する人気のQ&A

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

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Q共有メモリの使い方について

開発環境:Win2000 SP4 VB6.0 SP5

共有メモリを使用して、別プロセスとデータの受け渡しを
したいと思っております。
色々調べた結果、CreateFileMappingを使用するまでは、
理解できたのですが、受け渡すデータについて困っています。

受け取る際のデータの形式が
Public Type typXYData
xx(20000) As Long
yy(20000) As Long
End Type

のユーザー定義型なっていて、64KBを越える為に宣言が
できません。
このような場合はどうやって共有メモリからデータを
受け取ったらよいのでしょうか?

解かる方ご教授お願い致します。

Aベストアンサー

まずここ読む
http://techtips.belution.com/ja/vc/0001/

んで以下のサンプルをどうぞ。
思いっきりポインタ使っています。
ってか、APIを使用するならC同様、ポインタで扱います。

サンプルは二つのプロジェクトで、両方とも
・フォーム
・標準モジュール
の構成になっています。

標準モジュールは、Project1/Project2兼用です。



'''---------------------------------------------
'''---------- Project1.Form1 ここから ----------
'''---------------------------------------------
Option Explicit

Private pProcID   As Long
Private hProcess  As Long
Private pShared   As Long
Private pSharedLen As Long


Private Const DEF_PROJECT2     As String = "c:\Project2.exe"
Private Const DEF_MAX_ARRAY     As Long = 20000
Private pLngXX(1 To DEF_MAX_ARRAY) As Long


'別アプリ起動
Private Sub Command1_Click()
  On Error GoTo PGMERR

  Dim strParam  As String
  
  '別アプリ存在チェック
  If Dir(DEF_PROJECT2) = "" Then
    MsgBox "EXEがみつからない"
    GoTo PGMEND
  End If
  
  '共有メモリに値を書き込む
  If Not memWrite(hProcess, pShared, VarPtr(pLngXX(1)), pSharedLen) Then
    Call MsgBox("共有メモリへの書き込み失敗")
    GoTo PGMEND
  End If

  'パラメータ作成(プロセスID/配列要素数/共有メモリ先頭ポインタ)
  strParam = pProcID & " " & DEF_MAX_ARRAY & " " & pShared
  
  '起動
  Call Shell(DEF_PROJECT2 & " " & strParam)
  
PGMEND:
  Exit Sub

PGMERR:
  Call MsgBox(Err.Description, vbCritical)
  GoTo PGMEND
End Sub


'ロード
Private Sub Form_Load()
  Me.Command1.Caption = "別アプリ起動"
  Me.Command1.Enabled = False
  
  'プロセスIDを取得する
  If Not GetThreadProcessId(Me.hwnd, pProcID) Then
    Call MsgBox("プロセス情報取得失敗")
    GoTo PGMEND
  End If
  
  '共有メモリオープン
  pSharedLen = (Len(pLngXX(1)) * DEF_MAX_ARRAY)
  If Not memOpen(pProcID, pSharedLen, hProcess, pShared) Then
    Call MsgBox("共有メモリ確保失敗")
    GoTo PGMEND
  End If
  
  
  'ダミーの値をセット
  Call setValues
  
  Me.Command1.Enabled = True
  
PGMEND:
End Sub

'アンロード
Private Sub Form_Unload(Cancel As Integer)
  Call memFree(hProcess, pShared)
End Sub


'ダミー値セット
Private Sub setValues()
  Dim i    As Long
  
  '適当に乱数をセット
  For i = 1 To DEF_MAX_ARRAY
    pLngXX(i) = Int(30 * Rnd)
  Next i
End Sub
'''---------------------------------------------
'''---------- Project1.Form1 ここまで ----------
'''---------------------------------------------



'''---------------------------------------------
'''---------- Project2.Form1 ここから ----------
'''---------------------------------------------
Option Explicit

Private hProcess  As Long

Private Sub Form_Load()
  Dim strCmd   As String
  Dim varWk    As Variant
  
  strCmd = Command$
  If strCmd = "" Then
    MsgBox "パラメータなし"
    End
  End If
  
  'デバッグ用リストボックスクリア
  Me.List1.Clear
  
  'パラメータ分解
  varWk = Split(strCmd, " ")
  
  '読み取りと画面反映
  Call memDataRead(CLng(varWk(0)), CLng(varWk(1)), CLng(varWk(2)))
End Sub

'読み取りと画面反映
Private Sub memDataRead(ByVal inAppID As Long, ByVal inArrayCount As Long, ByVal lngMemPointer As Long)
On Error GoTo PGMEND
  Dim lngXX()   As Long
  Dim dwSize   As Long
  Dim i      As Long
  
  '配列領域確保
  ReDim lngXX(1 To inArrayCount) As Long
  
  'メモリサイズを取得
  dwSize = Len(lngXX(1)) * inArrayCount
  
  '共有メモリ確保
  If Not procOpen(inAppID, hProcess) Then
    Call MsgBox("共有メモリ確保失敗")
    GoTo PGMEND
  End If
  
  '共有メモリから値を読み込む
  If Not memRead(hProcess, lngMemPointer, VarPtr(lngXX(1)), dwSize) Then
    Call MsgBox("共有メモリからの読み込む失敗")
    GoTo PGMEND
  End If

  'デバッグ用リストボックスへ出力
  For i = 1 To inArrayCount
    Me.List1.AddItem lngXX(i)
  Next i
PGMEND:
  Call procFree(hProcess)
  Exit Sub
PGMERR:
  Call MsgBox(Err.Description, vbCritical)
  GoTo PGMEND
End Sub
'''---------------------------------------------
'''---------- Project2.Form1 ここまで ----------
'''---------------------------------------------



'''-----------------------------------------------
'''---------- Project1.Module1 ここから ----------
'''---------- Project2.Module1 ここから ----------
'''---------- 二つのプロジェクトで必要 ----------
'''-----------------------------------------------
Option Explicit

Private Declare Function OpenProcess Lib "kernel32" ( _
  ByVal dwDesiredAccess As Long, _
  ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function VirtualAllocEx Lib "kernel32" ( _
  ByVal hProcess As Long, _
  ByVal lpAddress As Long, _
  ByVal dwSize As Long, _
  ByVal flAllocationType As Long, _
  ByVal flProtect As Long) As Long
Private Declare Function VirtualFreeEx Lib "kernel32" ( _
  ByVal hProcess As Long, _
  ByVal lpAddress As Long, _
  ByVal dwSize As Long, _
  ByVal dwFreeType As Long) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" ( _
  ByVal hwnd As Long, _
  ByRef lpdwProcessId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" ( _
  ByVal hObject As Long) As Long
Private Declare Function WriteProcessMemory Lib "kernel32" ( _
  ByVal hProcess As Long, _
  ByVal lpBaseAddress As Long, _
  ByVal lpBuffer As Long, _
  ByVal nSize As Long, _
  ByRef lpNumberOfBytesWritten As Long) As Long
Private Declare Function ReadProcessMemory Lib "kernel32" ( _
  ByVal hProcess As Long, ByVal lpBaseAddress As Long, _
  ByVal lpBuffer As Long, _
  ByVal nSize As Long, _
  ByRef lpNumberOfBytesWritten As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)


Private Const STANDARD_RIGHTS_REQUIRED As Long = &HF0000
Private Const SYNCHRONIZE        As Long = &H100000

Private Const PROCESS_TERMINATE     As Long = &H1
Private Const PROCESS_CREATE_THREAD   As Long = &H2
Private Const PROCESS_SET_SESSIONID   As Long = &H4
Private Const PROCESS_VM_OPERATION   As Long = &H8
Private Const PROCESS_VM_READ      As Long = &H10
Private Const PROCESS_VM_WRITE     As Long = &H20
Private Const PROCESS_DUP_HANDLE    As Long = &H40
Private Const PROCESS_CREATE_PROCESS  As Long = &H80
Private Const PROCESS_SET_QUOTA     As Long = &H100
Private Const PROCESS_SET_INFORMATION  As Long = &H200
Private Const PROCESS_QUERY_INFORMATION As Long = &H400
Private Const PROCESS_ALL_ACCESS    As Long = STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or &HFFF

Private Const PAGE_NOACCESS       As Long = &H1
Private Const PAGE_READONLY       As Long = &H2
Private Const PAGE_READWRITE      As Long = &H4
Private Const PAGE_WRITECOPY      As Long = &H8
Private Const PAGE_EXECUTE       As Long = &H10
Private Const PAGE_EXECUTE_READ     As Long = &H20
Private Const PAGE_EXECUTE_READWRITE  As Long = &H40
Private Const PAGE_EXECUTE_WRITECOPY  As Long = &H80
Private Const PAGE_GUARD        As Long = &H100
Private Const PAGE_NOCACHE       As Long = &H200
Private Const PAGE_WRITECOMBINE     As Long = &H400

Private Const MEM_COMMIT        As Long = &H1000
Private Const MEM_RESERVE        As Long = &H2000
Private Const MEM_DECOMMIT       As Long = &H4000
Private Const MEM_RELEASE        As Long = &H8000
Private Const MEM_FREE         As Long = &H10000
Private Const MEM_PRIVATE        As Long = &H20000
Private Const MEM_MAPPED        As Long = &H40000
Private Const MEM_RESET         As Long = &H80000
Private Const MEM_TOP_DOWN       As Long = &H100000
Private Const MEM_4MB_PAGES       As Long = &H80000000

'プロセスオブジェクトのハンドルを開く
Public Function procOpen(ByVal inAppID As Long, otProc As Long) As Boolean
  otProc = OpenProcess(PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, 0, inAppID)
  If otProc = 0 Then
    GoTo PGMEND
  End If

  procOpen = True
PGMEND:
End Function

'プロセスオブジェクトのハンドルを開放する
Public Sub procFree(inProc As Long)
  Call CloseHandle(inProc)
  inProc = 0
End Sub

'共有メモリをオープン
Public Function memOpen(ByVal inAppID As Long, ByVal inSize As Long, otProc As Long, otSharedAddress As Long) As Boolean
  '共有メモリをクローズする
  Call memFree(otProc, otSharedAddress)
  
  'プロセスオブジェクトのハンドルを開く
  If Not procOpen(inAppID, otProc) Then
    GoTo PGMEND
  End If

  
  '共有メモリを開放する
  otSharedAddress = VirtualAllocEx(otProc, 0, inSize, MEM_RESERVE Or MEM_COMMIT, PAGE_READWRITE)
  If otSharedAddress = 0 Then
    GoTo PGMEND
  End If
  
  memOpen = True
PGMEND:
  If Not memOpen Then
    Call memFree(otProc, otSharedAddress)
  End If
End Function

'共有メモリをクローズ
Public Sub memFree(inProc As Long, inSharedAddress As Long)
  'クローズ
  Call VirtualFreeEx(inProc, inSharedAddress, 0, MEM_RELEASE)
  inSharedAddress = 0
  
  'プロセスオブジェクトのハンドルを開放する
  Call procFree(inProc)
End Sub

'共有メモリ領域に書き込む
Public Function memWrite(ByVal inProc As Long, ByVal inSharedAddress As Long, ByVal inMemPnt As Long, ByVal inSize As Long, Optional otSize As Long) As Boolean
  Dim lngSts As Long
  otSize = 0
  lngSts = WriteProcessMemory(inProc, inSharedAddress, ByVal inMemPnt, inSize, otSize)
  memWrite = (lngSts <> 0)
End Function

'共有メモリ領域から読み込む
Public Function memRead(ByVal inProc As Long, ByVal inSharedAddress As Long, ByVal inMemPnt As Long, ByVal inSize As Long, Optional otSize As Long) As Boolean
  Dim lngSts As Long
  otSize = 0
  lngSts = ReadProcessMemory(inProc, inSharedAddress, ByVal inMemPnt, inSize, otSize)
  memRead = (lngSts <> 0)
End Function

'ハンドルから、プロセスIDとスロッドIDを取得する
Public Function GetThreadProcessId(ByVal inWnd As Long, Optional otProcID As Long, Optional otThred As Long) As Boolean
  otProcID = 0
  otThred = 0
  otThred = GetWindowThreadProcessId(inWnd, otProcID)
  GetThreadProcessId = (otThred <> 0)
End Function
'''-----------------------------------------------
'''---------- Project1.Module1 ここまで ----------
'''---------- Project2.Module1 ここまで ----------
'''---------- 二つのプロジェクトで必要 ----------
'''-----------------------------------------------

参考URL:http://techtips.belution.com/ja/vc/0001/

まずここ読む
http://techtips.belution.com/ja/vc/0001/

んで以下のサンプルをどうぞ。
思いっきりポインタ使っています。
ってか、APIを使用するならC同様、ポインタで扱います。

サンプルは二つのプロジェクトで、両方とも
・フォーム
・標準モジュール
の構成になっています。

標準モジュールは、Project1/Project2兼用です。



'''---------------------------------------------
'''---------- Project1.Form1 ここから ----------
'''---------------------------------------------...続きを読む

Q他アプリの操作(メニューバー)

市販されているアプリケーションを自分で作成しているソフトで操作したいのですが、どの様に制御したらいいのか判りません。プログラムはVB6.0で作成しております。
したい事は他のアプリケーションでメニューバーの中の項目の
印刷項目を選択したいのですが、メニューバーのハンドルを取得
出来ず困っております。
そもそもメニューバーのハンドルって取得できるのでしょうか?

Aベストアンサー

ウィンドウハンドルの取得については割愛します。

Option Explicit

Private Declare Function GetMenu Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function GetMenuItemInfo Lib "user32" Alias "GetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long, ByVal b As Long, lpMenuItemInfo As MENUITEMINFO) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Const WM_COMMAND = &H111

Private Type MENUITEMINFO
cbSize As Long
fMask As Long
fType As Long
fState As Long
wID As Long
hSubMenu As Long
hbmpChecked As Long
hbmpUnchecked As Long
dwItemData As Long
dwTypeData As String
cch As Long
End Type

' hWndに指定したウィンドウのメニュークリックをエミュレート
' Menusには、メニューを辿る順序を文字列配列で定義
' ファイル -> 印刷 であれば Menus() = {"ファイル", "印刷"}
Private Sub EmulateMenuClick(ByVal hWnd As Long, Menus() As String)
Dim hMenu As Long, lngID As Long, intMenuIndex As Integer
hMenu = GetMenu(hWnd)

' メニュー階層をたどる
For intMenuIndex = 0 To UBound(Menus)

If ContainMenu(hMenu, Menus(intMenuIndex), lngID) = False Then
Call MsgBox("一致するメニューはありません。")
Exit Sub
End If

Next

' 最終的に見つかったメニューのIDをWM_COMMANDでPostMessage
Call PostMessage(hWnd, WM_COMMAND, lngID, 0&)
End Sub

' hMenuのメニューハンドル内でTextの文字列と一致するメニューがあるかどうかを返す
' 見つかればTrue。このとき、hMenuにはサブメニューのハンドル、IDにはメニューのIDが返される
' 見つからなければFalse
Private Function ContainMenu(hMenu As Long, ByVal Text As String, ID As Long) As Boolean
Dim lngCount As Long, lngPos As Long
Dim typMenuItem As MENUITEMINFO
lngCount = GetMenuItemCount(hMenu)

' メニューの個数でループ
For lngPos = 0 To lngCount - 1
typMenuItem.fMask = &H3F&

typMenuItem.dwTypeData = vbNullChar
typMenuItem.cch = 0
typMenuItem.cbSize = Len(typMenuItem)
Call GetMenuItemInfo(hMenu, lngPos, 1, typMenuItem)

typMenuItem.dwTypeData = String(typMenuItem.cch, " ")
typMenuItem.cch = typMenuItem.cch + 1
typMenuItem.cbSize = Len(typMenuItem)
Call GetMenuItemInfo(hMenu, lngPos, 1, typMenuItem)

Debug.Print typMenuItem.dwTypeData

' メニューの文字列を比較(比較方法はどちらでも)
'If typMenuItem.dwTypeData = Text Then
If typMenuItem.dwTypeData Like Text Then

' 一致したらIDとサブメニューハンドルを返す
ID = typMenuItem.wID
hMenu = typMenuItem.hSubMenu
ContainMenu = True
Exit Function
End If
Next

ContainMenu = False
End Function

EmulateMenuClickにウィンドウハンドルと実行したいメニューを辿る文字列配列を渡してください。
画像は、このコードを利用してAPIビューアのバージョン情報をForm1から実行して表示させたものです。

ウィンドウハンドルの取得については割愛します。

Option Explicit

Private Declare Function GetMenu Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function GetMenuItemInfo Lib "user32" Alias "GetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long, ByVal b As Long, lpMenuItemInfo As MENUITEMINFO) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA...続きを読む

QVBで他アプリの「syslistview32」のテキストを取得したい

VB6で他アプリの「syslistview32」のテキストを取得したいのです。
取得するためにはAPIを使用すると思うのですが、
使用するAPIが分かりません。

記述方法など分かる方、簡単でいいので教えて頂けるとありがたいです。

また、解説しているHP等がありましたら紹介頂けるとありがたいです。
よろしくお願いします。

Aベストアンサー

C++の例
http://www.est.hi-ho.ne.jp/getchan/junks/junk01.html

VBでの宣言例
http://wk.doubleukay.com/unlinked/source/LVMacros_471.bas

QEnumChildWindowsの使い方(VBA)

64bit版ExcelのVBAでEnumChildWindowsを使用して、子ウィンドウのウィンドウハンドルを
取得したいと考えています。
下記のようなサンプルを作ってみましたが、コールバック関数でExcelが異常終了します。
(05行目にブレークポイントを設定、各変数の値を参照しようとした時点でExcelが異常終了)

また、コールバック関数の第3引数(lParam)の型をInteger,Long,LongPtr等変えてみましたが、
いずれもExcelの異常終了となりました。

つきまして、64bit Excelでの本APIの使い方を教えていただきたくよろしくお願いいたします。
(なお、32bit版のExcelでは正常に動作しました)

<以下サンプルコード>
行 コード
01   Declare PtrSafe Function EnumChildWindows Lib "user32.dll" (ByVal ParenthWnd as LongPtr, ByVal EnumWindosPROC as LongPtr,ByVal lParam as Long) as Integer
02
03
04 Function ListupChildWindows(hWnd as LongPtr,lParam as Long) as Boolean
05 MsgBox hWnd
06 ListupChildWIndows =True
07 End Function
08
09 Sub test_CwinList
10 Dim ThishWnd as LongPtr
11
12 ThishWnd=Excel.Application.hWnd
13 Call EnumChildWindows (ThishWnd , AddressOf ListupChildWindows ,0)
14 End Sub

64bit版ExcelのVBAでEnumChildWindowsを使用して、子ウィンドウのウィンドウハンドルを
取得したいと考えています。
下記のようなサンプルを作ってみましたが、コールバック関数でExcelが異常終了します。
(05行目にブレークポイントを設定、各変数の値を参照しようとした時点でExcelが異常終了)

また、コールバック関数の第3引数(lParam)の型をInteger,Long,LongPtr等変えてみましたが、
いずれもExcelの異常終了となりました。

つきまして、64bit Excelでの本APIの使い方を教えていただきたくよろしくお...続きを読む

Aベストアンサー

こんにちは。

ご提示のサンプルですが、当方のVBA7x64環境でも
(実行の度に無条件で必ず)Excelの異常終了を再現できました。

この問題の解決については、私の力量を越えていますので、
情報提供、という形でお応えします。

『APPS PRO > VBA Tips > How Can I Locate a Specific Child Window Handle?』
http://www.appspro.com/Tips/VBA%20Tips.htm
こちらのページの一番下の[EnumChildWindows]をクリックすると
x32|x64両方対応のサンプルコードが入手できます。
そのままこちらで試してみた処、
(このサンプルは、ThisWorkbook.Windows(1)のハンドル'だけ'を取得するものなので)
エラーにはなりませんでした。
コールバック関数側で、条件分岐を書き換えてみたり、
無条件でWindowClassやWindowTitleを取得するよう試みたりして、
約30(重複を含む)の子ウィンドウのウィンドウハンドルが取得出来る所までは確認しましたが、
すべてを取得出来ていないか、うまく終了させることが出来ていないか、どちらかで、
完全な動作を確認するには至りませんでした。
デバッグのヒントにはなりそうな気はしますので、サンプル試してみては如何でしょう。

もしうまく行く方法があるとすれば、
WindowClassとWindowTitleでの条件分岐を整理して、
適切に列挙を終了させることになるような気がしています。
例えばThisWorkbook.Windows(1)のWindowClassとWindowTitleが確認できたら、
(そこから数えてx番目の子ウィンドウで、、、x = 0 かも?)
コールバック関数の戻りを0にして列挙を終了する、、、、みたいな?
或いは、特定の子ウィンドウに限定できるなら、同様にうまく扱えるようにも思えます。

実践的には、同じハンドルが重複して戻る場合があることを考慮して、
ハンドル列挙の受け皿としてCollectionオブジェクト等を用いることになるかと思いますが、
もしかしたら、この戻り値の重複についてもチェックしてみた方がいいのかも??知れません。

参考になるか解りませんが、以上です。

こんにちは。

ご提示のサンプルですが、当方のVBA7x64環境でも
(実行の度に無条件で必ず)Excelの異常終了を再現できました。

この問題の解決については、私の力量を越えていますので、
情報提供、という形でお応えします。

『APPS PRO > VBA Tips > How Can I Locate a Specific Child Window Handle?』
http://www.appspro.com/Tips/VBA%20Tips.htm
こちらのページの一番下の[EnumChildWindows]をクリックすると
x32|x64両方対応のサンプルコードが入手できます。
そのままこちらで試してみた処、
(このサ...続きを読む

QExcelVBAでAPIを使って外部ウインドウのエディットテキストを取得する方法

●やりたいこと
ExcelVBAで、APIを実行し、外部ソフトのウィンドウに含まれている
エディットテキストを取得して、セルに出力したい

使用する関数・宣言、できればコードを教えていただけませんでしょうか。

イメージはこちらをご参考いただけると幸いです。
​http://situmon-img.blogspot.com/2008/08/1.html​

変数hwindowに親ウィンドウのハンドルが取得されています。
エディットボックスのハンドル、IDは分かりません。


エディットボックスのハンドルを取得し、
分かっているクラス・ハンドルの文字列を取得
といった流れになるのではと思っております。

変数にさえ文字列が取得できれば、
当然ですが、Range("B2")=変数 で大丈夫です。
変数は、ひとつを使いまわしで構いません。
変数をエディットテキストの数だけ用意しても構いません。

Aベストアンサー

あの QNo.4256138の質問でも、同じ様な事を質問されていたと思います。
出来たらそちらで質問された方がよかったのではと思います。

テキストボックスの取得も、私の回答した全く同じ方法で
取得出来ると思います。クラス名が Edit になるだけです。

 EnumChildWindows(hWnd,lpEnumFunc,0&) は、親ウィンドウに含まれる

子ウィンドウがすべて返ってきます。ボタンもテキストボックスも、その他の
子ウィンドウがすべて、何個あっても、取得できます。

ただ EnumChildWindows(hWnd,lpEnumFunc,0&) で与える子ウィンドウを
受け取る関数は、コールバック関数なので、1回のコールで1個の子ウィンドウ
しか返ってきません。ただ、子ウィンドウがある分だけ何度も同じ関数が
呼び出されます。よび出される度に

 GetClassName(hWnd,lpClassName,nMaxCount) でクラス名を取得し

クラス名が Edit ならテキストボックスになります。

SendMessage(テキストボックスハンドル, &HD, 240, ByVal cbuf)

で cbuf にテキストボックスの文字が取得出来ます。

尚、cbuf は文字長を多い目に事前に確保しておきましょう。

cbufのNULL値までが実際の文字となります。

また、コールバック関数はデバッグモードで、ブレークさすと、
フリーズするので注意して下さい。通常はデバッグしにくいので、
コールバック関数内では、配列変数にハンドルをためこんでいきます。
その後で、配列にためこんでいるハンドルを順番にクラス名を取得し
テキストがボタンか判断していきます。

あの QNo.4256138の質問でも、同じ様な事を質問されていたと思います。
出来たらそちらで質問された方がよかったのではと思います。

テキストボックスの取得も、私の回答した全く同じ方法で
取得出来ると思います。クラス名が Edit になるだけです。

 EnumChildWindows(hWnd,lpEnumFunc,0&) は、親ウィンドウに含まれる

子ウィンドウがすべて返ってきます。ボタンもテキストボックスも、その他の
子ウィンドウがすべて、何個あっても、取得できます。

ただ EnumChildWindows(hWnd,lpEnumFunc,0...続きを読む

Qリストビューの選択状態を取得するメッセージはありますか?

リストビューが選択状態(1行が青色や灰色の背景になる状態)にあって、エディットボックスが空欄では無いときに、
あるボタンを有効にするという処理をしたいと思っています。

リストビューが選択されていることを教えてくれるメッセージがあれば、教えてください。よろしくお願いします。

環境:Win32 API, VC++6.0

Aベストアンサー

★アドバイス
>また話は少し変わってしまうのですが、リストビューに項目を追加したときに、
>その追加した行にフォーカスが合って、スクロールバーが自動的に下がってくるように
>することは可能でしょうか。
 ↑
 可能です。
 ListView_EnsureVisible( hList, 追加した行, TRUE );
 とします。これで自動的に最後に追加した行にスクロールします。
・あとちょっと不明な点がありますが、
 (1)追加した行にフォーカスを合わせるのか?
 (2)追加した行に範囲選択を設定するのか?
 どっちでしょうか。
 どちらにしても ListView_SetItemState() マクロで設定できますけど。
・(1)フォーカスを合わせる
 ListView_SetItemState( hList, 追加した行, LVIS_FOCUSED, LVIS_FOCUSED );
・(2)追加した行に範囲選択を設定する
 ListView_SetItemState( hList, 追加した行, LVIS_SELECTED, LVIS_SELECTED );
 とします。
※フォーカスと範囲選択は違います。注意。

>今回はある特定の行ではなく、リストビューのどこかの行が選択されているという
>イベントハンドラがあればと思っているのですが、そのようなものはあるのでしょうか。
 ↑
 イベントハンドラはないと思いますけど。
 その代わりに ListView_GetItemState()、ListView_GetNextItem() マクロのチェックで
 分かると思います。ListView_GetNextItem() で LVIS_SELECTED フラグを見つければ
 その行とかが分かると思います。
・あるいは先頭行から順番に ListView_GetItemState() マクロで LVIS_SELECTED フラグが
 立っている行を自分で検索するとかすれば良い。
 詳しくは下の『参考URL』をどうぞ。
・以上。

参考URL:http://www.geocities.jp/ekakibuta/Programing/ListView_GetNextItem.htm

★アドバイス
>また話は少し変わってしまうのですが、リストビューに項目を追加したときに、
>その追加した行にフォーカスが合って、スクロールバーが自動的に下がってくるように
>することは可能でしょうか。
 ↑
 可能です。
 ListView_EnsureVisible( hList, 追加した行, TRUE );
 とします。これで自動的に最後に追加した行にスクロールします。
・あとちょっと不明な点がありますが、
 (1)追加した行にフォーカスを合わせるのか?
 (2)追加した行に範囲選択を設定するのか?
 どっちでし...続きを読む

QVB6 API LISTVIEW(チェックボックス付き)にチェックを付けたい

CreateWindowExでLISTVIEW(チェックボックス付きのレポートビュー)を作ったのですが、「山田花子」行にソースでチェックを付ける方法が分かりません。

Form1のソース

Option Explicit

Private Sub Form_Load()

Dim lngRet As Long
Dim lvcol As LV_COLUMN
Dim rStyle As Long
Dim item As LV_ITEM

'-- リストビューの作成
hList = CreateWindowEx(WS_EX_CLIENTEDGE, _
WC_LISTVIEW, "", _
WS_CHILD Or WS_VISIBLE Or WS_BORDER Or _
WS_CLIPSIBLINGS Or WS_CLIPCHILDREN Or _
LVS_REPORT, _
0&, 0&, Me.ScaleWidth / Screen.TwipsPerPixelX, 200&, _
Me.hwnd, _
0&, _
App.HINSTANCE, _
ByVal 0&)

'拡張スタイルを設定
rStyle = rStyle Or LVS_EX_FULLROWSELECT Or LVS_EX_GRIDLINES Or LVS_EX_CHECKBOXES
SendMessageByNum hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0&, rStyle

'-- カラムヘッダーの追加
With lvcol

.mask = LVCF_FMT Or LVCF_WIDTH Or LVCF_TEXT Or LVCF_SUBITEM
.fmt = LVCFMT_LEFT
.cx = 100
.pszText = "名前"
.iSubItem = 0
lngRet = ListView_InsertColumn(hList, 0&, lvcol)

End With

'-- リストアイテムの追加
With item

.mask = LVIF_TEXT Or LVIF_IMAGE

' 1つめ
.pszText = "山田 太郎"
.iItem = 0
.iSubItem = 0
.iImage = 0
lngRet = ListView_InsertItem(hList, item)

' 2つめ
.pszText = "山田 花子"
.iItem = 1
.iSubItem = 0
.iImage = 1
lngRet = ListView_InsertItem(hList, item)

End With

End Sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
'-- リストビューを破棄
DestroyWindow hList
End Sub

標準モジュールは補足に書きます

CreateWindowExでLISTVIEW(チェックボックス付きのレポートビュー)を作ったのですが、「山田花子」行にソースでチェックを付ける方法が分かりません。

Form1のソース

Option Explicit

Private Sub Form_Load()

Dim lngRet As Long
Dim lvcol As LV_COLUMN
Dim rStyle As Long
Dim item As LV_ITEM

'-- リストビューの作成
hList = CreateWindowEx(WS_EX_CLIENTEDGE, _
WC_LISTVIEW, "", _
WS_CH...続きを読む

Aベストアンサー

LVITEMのstateMaskとstateメンバを適切に設定してLVM_SETITEMSTATEメッセージを送ればいいようです

Pubic Sub ListView_SetCheckState( hWnd as long, n as long, bflag as integer)
Const LVM_SETITMSTATE = (LVM_FIRST + 43)
  dim oItem as LVITEM
  dim bit as integer
  if bflag then
    bit = &h2000
  else
    bit = &h1000
  end if
  oItem.stateMask = &HF000
  oItem.state = bit

  SendMessage hWnd, LVM_SETITEMSTATE, n, oItem
End Sub

チェック状態の取得は
Pubic Function ListView_GetCheckState( hWnd as long, n as long ) as integer
  Const LVM_GETITMSTATE = (LVM_FIRST + 44)
  dim state as long
  state = SendMessage( hWnd, LVM_GETITEMSTATE, n, &HF000) / 4096
  ListView_GetCheckState = state - 1
End Function

といった具合だと思います

LVITEMのstateMaskとstateメンバを適切に設定してLVM_SETITEMSTATEメッセージを送ればいいようです

Pubic Sub ListView_SetCheckState( hWnd as long, n as long, bflag as integer)
Const LVM_SETITMSTATE = (LVM_FIRST + 43)
  dim oItem as LVITEM
  dim bit as integer
  if bflag then
    bit = &h2000
  else
    bit = &h1000
  end if
  oItem.stateMask = &HF000
  oItem.state = bit

  SendMessage hWnd, LVM_SETITEMSTATE, n, oItem
End Sub

チェック状...続きを読む

Q親ウインドウにあるOKボタンを押す方法

非常に基本的なことを質問して申し訳ございません。

●やりたいこと●
ある親ウィンドウに「テキスト」と「OKボタン」があります。
OKボタンはひとつだけです。
このOKボタンを押して、親ウィンドウを閉じるだけです。
OKボタンを押せば、親ウィンドウは勝手に閉じます。


親ウィンドウのハンドルは取得できたのですが、
子ウィンドウ(ボタン"OK")のハンドルが取得できず、
その後の処理もできておりません。

ボタンはひとつだけなので、ボタンのハンドルを検索したりしなくても、
押すことはできるような気がするのですが・・・
初心者の浅知恵で申し訳ございません。

やはり、ボタンのハンドルを取得して、押すコマンドを実行しないといけないのでしょうか?

ボタンのハンドルを取得して、押すコマンドを実行する場合、
その方法を教えていただけると幸いです。

親ウィンドウのハンドルは変数「hWindow」に入っているとして、
コードをお願いいたします。

親ウィンドウのハンドル取得に使ったFindWindow以外に宣言が必要であればご教授お願いいたします。

非常に基本的なことを質問して申し訳ございません。

●やりたいこと●
ある親ウィンドウに「テキスト」と「OKボタン」があります。
OKボタンはひとつだけです。
このOKボタンを押して、親ウィンドウを閉じるだけです。
OKボタンを押せば、親ウィンドウは勝手に閉じます。


親ウィンドウのハンドルは取得できたのですが、
子ウィンドウ(ボタン"OK")のハンドルが取得できず、
その後の処理もできておりません。

ボタンはひとつだけなので、ボタンのハンドルを検索したりしなくても、
押すことはでき...続きを読む

Aベストアンサー

子ウィンドウを探すには、下の2つのAPIの使います。

  EnumChildWindows(hWnd,lpEnumFunc,0&)
  GetClassName(hWnd,lpClassName,nMaxCount)

EnumChildWindows が、親ウィンドウのハンドルと、子ウィンドウを受け取る関数を
与えます。ただし、子ウィンドウを受け取る関数はフォームモジュールではなく、
標準モジュールにないと駄目です。

すると与えた子ウィンドウを受け取る関数に、親ウィンドウに含まれる全ての子ウィンドウの
ハンドルが返ってきます。

返ってきたハンドルを元に GetClassName で、クラス名を取得し、ボタンのウィンドウを
特定します。今回の場合は、ボタンが1個しかないとのことなので、取得したクラス名が
Buttonであればそのハンドルがボタンのハンドルになります。
参考までに、複数個のボタンがあれば、この場合、どのボタンがOKボタンなのかを特定しない
といけません。「スパイ」とか言うソフトがあれば簡単に特定できるのですが、ない場合は、
子ウィンドウに含まれる、上記の手順で得た全てのボタンのハンドルに対して、プログラムで
BM_CLICKのメッセージを送り一つづつ確認していくしかありません。ただこの場合でも、
特性があって、親ウィンドウに複数個のボタンがあっても、子ウィンドウを受け取る関数には
必ず一定の順番にしか、ハンドルが返ってきないので、最初に一度だけ何番目のボタンかを特定
すればよいです。対象のアプリケーションを再度起動してもこの順番は変わりません。

あと、ボタンのクリックは、SendMessageで、BM_CLICK を送ればOKです。

今回は、簡単な他アプリの制御なので、そんなに問題がないですが、複雑な制御だと、
更に、ウエイトの方法だとか、制御するアプリが確実に動作しているか、確認する操作を
1ステップずつ挿入していかないと駄目です。そうすれば、全ての他のアプリケーションを
自由に操る事ができます。

本格的に作るとなると大変なので、フリーのソフトで沢山でていると思います。一度さがされたら
よいと思います。DLLタイプになっているのがよいとは思います。
以前私も使ったことがありますが、憶えていません。あしからず。現在は自作しております。
自作のがよりきめ細かく制御出来るからです。

子ウィンドウを探すには、下の2つのAPIの使います。

  EnumChildWindows(hWnd,lpEnumFunc,0&)
  GetClassName(hWnd,lpClassName,nMaxCount)

EnumChildWindows が、親ウィンドウのハンドルと、子ウィンドウを受け取る関数を
与えます。ただし、子ウィンドウを受け取る関数はフォームモジュールではなく、
標準モジュールにないと駄目です。

すると与えた子ウィンドウを受け取る関数に、親ウィンドウに含まれる全ての子ウィンドウの
ハンドルが返ってきます。

返ってきたハンドルを元に G...続きを読む

QEXCEL VBAから他アプリケーションを操作することは可能ですか?

こんばんは。

VBAの本を購入し勉強していますが、VBAと他アプリケーションとの連携について記載が少なく(txtやcsvファイル操作)、どこまで出来るんだろうという不安があり質問しました。

(1)EXCEL VBAから他アプリケーションを起動し、設定操作、命令を送り操作することは可能でしょうか?
イメージとしては他アプリに一方的に命令を送り操作できれば良しです。(アプリ側からのリターン要求はしません。)

(2)第2の質問です。
VBAで他アプリを起動した状態で人が操作している感覚でマウスを操作できますか?(利用方法:他アプリの●ボタンを押したい!!)
目の前にソフトがあるのに触る操作は出来ないものでしょうか?
いろいろ調べて見ましたが、この様な事例はありません。
駄目元ですが、こんな操作を知っていましたら教えてください。
こんな操作ができればいいな~

Aベストアンサー

#2,4 です。

> EXCEL2000内の特定のセルに規定値外のデータが入力された場合に
> UWSCを起動して...

UWSC のスクリプトが完成しているとすれば、起動オプション付きで
バッチ処理すれば良いでしょう。実行タイミングは、シートまたは
ThisWorkbook の Change イベントが使えます。

例)シートモジュール

Private Const EXE_PATHNAME As String = "C:\Program Files\uwsc\uwsc.exe"
Private Const DQ      As String = """"

Private Sub Worksheet_Change(ByVal Target As Range)

  Dim rChange   As Range
  Dim sCommand  As String
  Dim sScriptFile As String

  ' // 実行する UWSC スクリプト
  sScriptFile = "C:\sample.uws"
  ' // UWSC の起動オプションは UWSC のヘルプを参照
  sCommand = DQ & EXE_PATHNAME & DQ & " " & _
        DQ & sScriptFile & DQ
  
  ' // 変更されたのが単一セルかつ A 列でなければ終了
  If Target.Cells.Count > 1 Then Exit Sub
  Set rChange = Intersect(Target, Columns("A"))
  If rChange Is Nothing Then
    Exit Sub
  End If
  
  ' // さらに値が TEST だった場合のみ実行
  If rChange.Value = "TEST" Then
    Shell sCommand, vbNormalFocus
  End If

End Sub

#2,4 です。

> EXCEL2000内の特定のセルに規定値外のデータが入力された場合に
> UWSCを起動して...

UWSC のスクリプトが完成しているとすれば、起動オプション付きで
バッチ処理すれば良いでしょう。実行タイミングは、シートまたは
ThisWorkbook の Change イベントが使えます。

例)シートモジュール

Private Const EXE_PATHNAME As String = "C:\Program Files\uwsc\uwsc.exe"
Private Const DQ      As String = """"

Private Sub Worksheet_Change(ByVal Target As Range)

  ...続きを読む

Q【C#】FindWindowExの使い方を教えてください

はじめまして
Visual Studio 2005を使用しています。
C#.NETは、いじり初めて1週間の超初心者です。
C#.NETでのFindWindowExの使い方を教えてください。
まずはじめに、vb.netで作ったアプリAの"Form1"があり、その中にテキストボックス"TextBox1"があります。
"TextBox1"のテキスト(キャプション?)には同じく"TextBox1"と入力されています。

そこで、C#側のアプリBでVBのアプリAの"Form1"のハンドルをFindWindowで取得します。
ここまでは出来ました。
次に、FindWindowExを使って"TextBox1"のハンドルを取得したいのですが、どうしてもうまく取得できません(0が返ってきます)

以下、C#のソースです。
(textBox1のMultilineはTrueです)
==================================================================

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsApplication1
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern IntPtr FindWindowEx(IntPtr hWnd, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

public IntPtr hWnd = (IntPtr)0;

public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
IntPtr hWnd;
IntPtr hWndTest;
string sClassName = null;
string sWindowText = "AppA";

// アプリAのウインドウハンドルを取得
hWnd = FindWindow(sClassName, sWindowText);
textBox1.Text = "ウインドウのハンドル " + hWnd + "\r\n";

// アプリAのウインドウ内のTextBox1のハンドルを取得
hWndTest = hWnd;
sClassName = null;
sWindowText = "TextBox1";
hWnd = FindWindowEx(hWndTest, IntPtr.Zero, sClassName, sWindowText);
textBox1.Text += "テキストボックスのハンドル " + hWnd;

}
}
}

==================================================================

Spy++で覗くとテキストボックスにもハンドルが割り与えられているので取得できるはずだと思っているのですが、どうしてもいまくいきません。
どうか、よろしくご享受願います。

ちなみに、アプリAのテキストボックスのクラス名が”WindowsForms10.EDIT.app.0.378734a”となっているのですが、これはどの環境でビルド(コンパイル)しても不変なのでしょうか?
不変だとしたら、クラス名を使えば悩まずに取得できると思うのですが・・・(実験済み)

はじめまして
Visual Studio 2005を使用しています。
C#.NETは、いじり初めて1週間の超初心者です。
C#.NETでのFindWindowExの使い方を教えてください。
まずはじめに、vb.netで作ったアプリAの"Form1"があり、その中にテキストボックス"TextBox1"があります。
"TextBox1"のテキスト(キャプション?)には同じく"TextBox1"と入力されています。

そこで、C#側のアプリBでVBのアプリAの"Form1"のハンドルをFindWindowで取得します。
ここまでは出来ました。
次に、FindWindowExを使って"TextBox1"のハン...続きを読む

Aベストアンサー

FindWindowExの中でGetWidnowTextを呼び出しているため失敗するのだと思いますよ

GetWidnowTextはプロセスを超えては取得できないようです
取得できたとしても間違ったデータを返す場合があるようです
MSDNなどの GetWindowTextを確認してみてください

プロセスを超えて子コントロールのテキストを取得する場合は
WM_GETTEXTを直接コントロールにSendMessageで送って取得するようにしないといけないようです

Spy++は GetWindowで子コントロールのハンドルを取得してタイトルの取得にはWM_GETTEXTをSendMessageで送っているのではないかと思われます

VB.NETのAppAのテキストボックスのデータを書き換えても起動時に設定してあったデータで無いと失敗するようです


人気Q&Aランキング

おすすめ情報