🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

解決済

1回答

2450閲覧

Windows10のデスクトップアイコンのファイル名の取得方法について

Markn

総合スコア7

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

2クリップ

投稿2018/04/07 07:28

前提・実現したいこと

Windowsのデスクトップアイコンの位置とファイル名を取得するマクロを作成しています。

発生している問題・エラーメッセージ

Windows7ではうまく動いたのですが、Windows10ではファイル名が取得できません。(ブランクになってしまう)

該当のソースコード

Excel

1Option Explicit 2 3'ウィンドウ検索 4Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ 5 (ByVal lpClassName As String, _ 6 ByVal lpWindowName As String) As Long 7 8'ウィンドウ取得 9Private Declare Function GetWindow Lib "user32" _ 10 (ByVal hwnd As Long, _ 11 ByVal uCmd As Long) As Long 12 13'ウィンドウへのメッセージ送付 14Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _ 15 (ByVal hwnd As Long, _ 16 ByVal wMsg As Long, _ 17 ByVal wParam As Long, _ 18 ByVal lParam As Any) As Long 19 20'ウィンドウのプロセスIDとスレッドIDを取得 21Private Declare Function GetWindowThreadProcessId Lib "user32" _ 22 (ByVal hwnd As Long, _ 23 lpdwProcessId As Long) As Long 24 25'プロセスOpen 26Private Declare Function OpenProcess Lib "kernel32" _ 27 (ByVal dwDesiredAccess As Long, _ 28 ByVal bInheritHandle As Long, _ 29 ByVal dwProcessId As Long) As Long 30 31'仮想メモリ確保 32Private Declare Function VirtualAllocEx Lib "kernel32" _ 33 (ByVal hProcess As Long, _ 34 ByVal lpAddress As Long, _ 35 ByVal dwSize As Long, _ 36 ByVal flAllocationType As Long, _ 37 ByVal flProtect As Long) As Long 38 39'仮想メモリ解放 40Private Declare Function VirtualFreeEx Lib "kernel32" _ 41 (ByVal hProcess As Long, _ 42 lpAddress As Any, _ 43 ByVal dwSize As Long, _ 44 ByVal dwFreeType As Long) As Long 45 46'ハンドルクローズ 47Private Declare Function CloseHandle Lib "kernel32" _ 48 (ByVal hObject As Long) As Long 49 50'ウィンドウ位置・サイズ取得 51Private Declare Function GetWindowRect Lib "user32" _ 52 (ByVal hwnd As Long, _ 53 lpRect As RECT) As Long 54 55'メモリへの書込み 56Private Declare Function WriteProcessMemory Lib "kernel32" _ 57 (ByVal hProcess As Long, _ 58 lpBaseAddress As Any, _ 59 lpBuffer As Any, _ 60 ByVal nSize As Long, _ 61 lpNumberOfBytesWritten As Long) As Long 62 63'メモリからの読込み 64Private Declare Function ReadProcessMemory Lib "kernel32" _ 65 (ByVal hProcess As Long, _ 66 lpBaseAddress As Any, _ 67 lpBuffer As Any, _ 68 ByVal nSize As Long, _ 69 lpNumberOfBytesWritten As Long) As Long 70 71'============== 72' ユーザ定義型 73'============== 74 75'リストビューアイテム構造体 76Private Type LV_ITEM 77 mask As Long 78 iItem As Long 79 iSubItem As Long 80 state As Long 81 stateMask As Long 82 lpszText As Long 83 cchTextMax As Long 84 iImage As Long 85 lParam As Long 86 iIndent As Long 87End Type 88 89'データエリア構造体 90Type LV_TEXT 91 sItemText As String * 80 92End Type 93 94'サイズ・位置情報構造体 95Public Type RECT 96 Left As Long 97 Top As Long 98 Right As Long 99 Bottom As Long 100End Type 101 102 103'========== 104' 定数定義 105'========== 106 107Private Const LVM_GETITEMCOUNT As Long = &H1004 108Private Const LVM_GETITEM As Long = &H1005 109Private Const LVM_GETITEMRECT As Long = &H100E 110Private Const LVM_SETITEMPOSITION As Long = &H100F 111Private Const LVM_SETEXTENDEDLISTVIEWSTYLE = &H1036 112Private Const LVM_GETEXTENDEDLISTVIEWSTYLE = &H1037 113 114Private Const LVS_EX_SNAPTOGRID = &H80000 115 116Private Const GW_CHILD As Long = 5 117 118Private Const LVIR_BOUNDS As Long = 0 119Private Const LVIR_ICON As Long = 1 120Private Const LVIR_LABEL As Long = 2 121Private Const LVIR_SELECTBOUNDS As Long = 3 122 123Private Const LVIF_TEXT = &H1 124 125Private Const PROCESS_VM_OPERATION = &H8 126Private Const PROCESS_VM_READ = &H10 127Private Const PROCESS_VM_WRITE = &H20 128 129Private Const MEM_COMMIT = &H1000 130Private Const MEM_RESERVE = &H2000 131Private Const MEM_DECOMMIT = &H4000 132Private Const MEM_RELEASE = &H8000 133 134Private Const PAGE_READWRITE = &H4& 135 136 137'共有メモリ確保 138Public Function GetSharedMem(ByVal pid As Long, ByVal memSize As Long, hProc As Long) As Long 139 hProc = OpenProcess(PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, False, pid) 140 GetSharedMem = VirtualAllocEx(ByVal hProc, ByVal 0&, ByVal memSize, MEM_RESERVE Or MEM_COMMIT, PAGE_READWRITE) 141End Function 142 143'共有メモリ開放 144Public Sub FreeSharedMem(ByVal hProc As Long, ByVal MemAddress As Long, ByVal memSize As Long) 145 Call VirtualFreeEx(hProc, ByVal MemAddress, memSize, MEM_RELEASE) 146 CloseHandle hProc 147End Sub 148 149 150Sub get_icon_pos_name() 151 152 '変数定義 153 Dim lngTopWindow As Long 'Topウィンドウのウィンドウハンドル 154 Dim lngChildWindow As Long '子ウィンドウのウィンドウハンドル 155 Dim lngSysListView32 As Long 'デスクトップのウィンドウハンドル 156 Dim rc As RECT '位置・サイズ格納用 157 158 Dim pid As Long 'プロセスID 159 Dim tid As Long 'スレッドID 160 Dim hProc As Long 'プロセスハンドル 161 Dim li As LV_ITEM 'パラメータ 162 Dim lt As LV_TEXT 'テキストエリア 163 Dim lpShared1 As Long 'パラメータエリア 164 Dim lpShared2 As Long 'データエリア 165 Dim lpShared3 As Long '位置 166 Dim lWritten As Long '書込済バイト数 167 Dim lngRC As Long '処理結果格納用 168 Dim maxitem As Long 'デスクトップのアイコン数 169 Dim i As Long 'ループカウンタ 170 Dim p As Long 'テキスト終端文字列の位置 171 Dim iconName As String 'アイコンの名前 172 Dim NetObj As Object 'NetworkObject 173 Dim strCompName As String 'コンピュータ名 174 175 'ExplorerのTopウィンドウを見つける 176 lngTopWindow = FindWindow("Progman", "Program Manager") 177 178 'Topウィンドウが見つかった時 179 If lngTopWindow Then 180 181 '子ウィンドウを取得 182 lngChildWindow = GetWindow(lngTopWindow, GW_CHILD) 183 184 '子ウィンドウが取得できたとき 185 If lngChildWindow Then 186 187 'さらにその子ウィンドウを取得(これがデスクトップ) 188 lngSysListView32 = GetWindow(lngChildWindow, GW_CHILD) 189 190 'デスクトップのウィンドウが取得できたとき 191 If lngSysListView32 Then 192 193 'デスクトップサイズの取得 194 GetWindowRect lngSysListView32, rc 195 196 197 'デスクトップアイコンの数を取得 198 maxitem = SendMessage(lngSysListView32, _ 199 LVM_GETITEMCOUNT, _ 200 0&, _ 201 ByVal 0&) 202 203 'コンピュータ名を取得 204 Set NetObj = CreateObject("WScript.Network") 205 strCompName = NetObj.ComputerName 206 Set NetObj = Nothing 207 208 'デスクトップのプロセスIDとスレッドIDを取得 209 tid = GetWindowThreadProcessId(lngSysListView32, pid) 210 211 'デスクトップとの共有メモリを確保(アドレスが返ってくる) 212 lpShared1 = GetSharedMem(pid, LenB(li), hProc) 'リストビュー構造体 213 lpShared2 = GetSharedMem(pid, LenB(lt), hProc) '取得文字列用 214 lpShared3 = GetSharedMem(pid, LenB(rc), hProc) 'アイコン位置用 215 216 217 'デスクトップのアイコン数分ループする 218 For i = 0 To maxitem - 1 219 220 'LVM_GETITEMへSendMessageする際のパラメータを設定 221 li.mask = LVIF_TEXT '文字情報取得 222 li.iItem = i '行インデックス 223 li.iSubItem = 0 '列インデックス 224 li.lpszText = lpShared2 '文字格納アドレス 225 li.cchTextMax = LenB(lt) '文字数最大値 226 227 'ローカル変数の値を共有メモリに書き込み 228 lngRC = WriteProcessMemory(hProc, ByVal lpShared1, li, LenB(li), lWritten) 229 lngRC = WriteProcessMemory(hProc, ByVal lpShared2, lt, LenB(lt), lWritten) 230 231 'デスクトップに対して情報の取得依頼(ファイル名) 232 lngRC = SendMessage(lngSysListView32, LVM_GETITEM, 0, ByVal lpShared1) 233 234 '共有メモリからローカル変数に読み込み 235 lngRC = ReadProcessMemory(hProc, ByVal lpShared2, lt, LenB(lt), lWritten) 236 237 'アイコン名を初期化 238 iconName = "" 239 240 '文字数を取得(終端文字がNullCharなのでその前まで) 241 p = InStr(lt.sItemText, vbNullChar) - 1 242 243 '空っぽでなければ 244 If p > 0 Then 245 246 'アイコン名を取得 247 iconName = Left(lt.sItemText, p) 248 249 End If 250 251 'LVM_GETITEMRECTへSendMessageする際のパラメータを設定 252 rc.Left = LVIR_ICON 'アイコンの外接する四角形サイズ取得 253 254 'ローカル変数の値を共有メモリに書き込み 255 lngRC = WriteProcessMemory(hProc, ByVal lpShared3, rc, LenB(rc), lWritten) '書込み 256 257 'デスクトップに対して情報の取得依頼(アイコン位置) 258 lngRC = SendMessage(lngSysListView32, LVM_GETITEMRECT, i, ByVal lpShared3) '取得依頼 259 260 '共有メモリからローカル変数に読み込み 261 lngRC = ReadProcessMemory(hProc, ByVal lpShared3, rc, LenB(rc), lWritten) '読込 262 263 Debug.Print "No. :" & i 264 Debug.Print "TOP :" & rc.Top 265 Debug.Print "LEFT :" & rc.Left 266 Debug.Print "RIGHT :" & rc.Right 267 Debug.Print "BOTTOM :" & rc.Bottom 268 Debug.Print "iconName:" & iconName 269 270 Next 271 272 '共有メモリ開放 273 FreeSharedMem hProc, lpShared1, LenB(li) 274 FreeSharedMem hProc, lpShared2, LenB(lt) 275 FreeSharedMem hProc, lpShared3, LenB(rc) 276 277 End If 278 End If 279 End If 280End Sub 281 282

試したこと

共有メモリの使い方等、色々調べてみたのですが、原因が分からないので質問させていただきました。

補足情報(FW/ツールのバージョンなど)

Excel 2010 VBA

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

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

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

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

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

guest

回答1

0

ベストアンサー

うまく動かなかった Windows 10 環境は 64 ビットではないでしょうか?
その場合、構造体のアライメントの問題で提示されているコードは正しく動作しません。
下記のようにアライメントを 64 ビットに合わせるためにフィールドを追加する必要があります。

VBA

1Private Type LV_ITEM 2 mask As Long 3 iItem As Long 4 iSubItem As Long 5 state As Long 6 stateMask As Long 7 dummy1 As Long 8 lpszText As Long 9 dummy2 As Long 10 cchTextMax As Long 11 iImage As Long 12 lParam As Long 13 iIndent As Long 14End Type

上記の変更を実施すると 32 ビット環境では動作しなくなります。両方の環境で動作させるためには構造体の定義をそれぞれ持つことになります。

また、デスクトップのリストビューのウィンドウハンドルが取れていないのであれば、ウィンドウハンドルを取得する方法を変更する必要があります。Windows 7 以降ではデスクトップの親ウィンドウのクラス名が Progman ではないことがあります。そのため以下に示すようにウィンドウのクラス名が WorkerW のウィンドウを検索する必要があります。

VBA

1 2'ウィンドウ検索Ex 3Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _ 4 (ByVal hwndParent As Long, _ 5 ByVal hwndChildAfter As Long, _ 6 ByVal lpClassName As String, _ 7 ByVal lpWindowName As String) As Long 8 9Function FindDesktopListView(ByVal topWindowClassName As String) As Long 10 11 Dim lngTopWindow As Long 12 Dim lngChildWindow As Long 13 14 lngTopWindow = FindWindowEx(0, 0, topWindowClassName, vbNullString) 15 Do 16 lngChildWindow = FindWindowEx(lngTopWindow, 0, "SHELLDLL_DefView", vbNullString) 17 If lngChildWindow <> 0 Then 18 FindDesktopListView = FindWindowEx(lngChildWindow, 0, vbNullString, vbNullString) 19 Exit Function 20 End If 21 lngTopWindow = FindWindowEx(0, lngTopWindow, topWindowClassName, vbNullString) 22 Loop While lngTopWindow <> 0 23 24End Function 25 26Sub get_icon_pos_name() 27 ... 28 29 lngSysListView32 = FindDesktopListView("Progman") 30 If lngSysListView32 = 0 Then 31 lngSysListView32 = FindDesktopListView("WorkerW") 32 End If

上記以外ではメモリおよびハンドルが解放できていない問題があります。VirtualFreeEx に MEM_RELEASE を指定する場合、解放するメモリのサイズを指定してはなりません。その場合、パラメータ違反で解放が失敗します。また、OpenProcess と CloseHandle は全体処理で1回のみ実行すれば良く現在のコードでは正しくハンドルが解放できていません。GetSharedMem と FreeSharedMem は以下のようにハンドルの取得と解放を行わないように修正し、OpenProcess と CloseHandle の呼び出しは GetSharedMem 前に OpenProcess を1回だけ呼び出し、すべての FreeSharedMem が終了した後で CloseHandle を呼び出すようにしましょう。

VBA

1Public Function GetSharedMem(ByVal hProc As Long, ByVal memSize As Long) As Long 2 GetSharedMem = VirtualAllocEx(ByVal hProc, ByVal 0&, ByVal memSize, MEM_RESERVE Or MEM_COMMIT, PAGE_READWRITE) 3End Function 4 5Public Sub FreeSharedMem(ByVal hProc As Long, ByVal MemAddress As Long) 6 Call VirtualFreeEx(hProc, ByVal MemAddress, 0, MEM_RELEASE) 7End Sub

投稿2018/04/08 15:19

atata0319

総合スコア881

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

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

Markn

2018/04/09 13:48

アライメントを修正したら、アイコン名が取得できるようになりました。Windows10の環境が64bit版だったからなんですね。 親ウィンドウのクラス名の取得方法やメモリやハンドルの解放等、まだまだ知識不足のところがあり、大変勉強になりました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問