最近ではきっと少なくなっているであろうAccessです。
業務で少しはまったのでメモとして残しておきます。
表題の通りです。
Accessのレポート表示の際に、1ページ目ではなく指定ページを表示する方法です。
環境
・Windows10、Windows7
・Access 2010、Access runtime 2010
必須ツール
・Spy++(ウィンドウハンドルのクラス名を調べるのに使用します)
概要
今回のシステムでは、レポートの起動方法として2パターンありました。
- レポートビュー(ポップアップなし)
- レポートビュー(ポップアップあり)
共に起動方法は以下になります。
DoCmd.OpenReport "レポート名", acViewPreview
どちらもAccess標準ではできないことなので、WindowsAPIを使用します。
レポートビュー(ポップアップなし)
こちらは簡単です。
レポート自体がキーボードの矢印キー(←→)でページ移動できますので、その命令を送ってあげればいいだけです。
SendKeys "{RIGHT}"
汎用的にするために、ユーティリティ関数を作って関数化してあげるといいかもしれませんね。
Public Function ReportMoveNextPage()
SendKeys "{RIGHT}"
End Function
レポートを起動する部分はこうなります。
移動したいページ分ReportMoveNextPageを実行してあげればよいです。
ただ、移動ページ数が多い場合は面倒なのでポップアップありの方法をとった方がいいかもしれません。
DoCmd.OpenReport "レポート名", acViewPreview
WindowsUtility.ReportMoveNextPage
今回の場合は2ページ目を表示したいだけだったので、以下のようにしました。
Dim firstFlag As Boolean
Private Sub Report_Load()
firstFlag = True
End Sub
Private Sub ページフッターセクション_Format(Cancel As Integer, FormatCount As Integer)
If firstFlag Then
'初期表示の場合のみ2ページ目を初期表示とする
WindowsUtility.ReportMoveNextPage
firstFlag = False
End If
End Sub
レポートビュー(ポップアップあり)
こちらはやや手間がかかります。
矢印キーでページ移動ができないため、レポート下部のページ番号を手動で変更してあげる必要があります。
WindowsAPIの定義
まず、使用する関数を定義します。
ポップアップなしで作成したユーティリティ関数に以下を追加します。
' Windowハンドルの検索
Public Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
' 親ハンドルを指定して検索
Public Declare PtrSafe Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" _
(ByVal hwndParent As Long, ByVal hwndChildAfter As Long, _
ByVal lpszClass As String, ByVal lpszWindow As String) As Long
' ウィンドウタイトル取得
Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _
(ByVal hWnd&, ByVal lpString$, ByVal cch&) As Long
' ウィンドウタイトル変更
Public Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String) As Long
処理関数の追加
続いて、以下の関数を追加します。
説明は後ほど。
Public Sub ReportMovePage()
Dim windowHandle As Long
windowHandle = WindowsUtility.FindWindow("OReportPopup", vbNullString) 'レポートのハンドルを取得
'配下のページ番号部分のハンドルを取得
If windowHandle <> 0 Then
windowHandle = WindowsUtility.FindWindowEx(windowHandle, 0, "OSUI", vbNullString)
End If
If windowHandle <> 0 Then
windowHandle = WindowsUtility.FindWindowEx(windowHandle, 0, "NetUINativeHWNDHost", vbNullString)
End If
If windowHandle <> 0 Then
windowHandle = WindowsUtility.FindWindowEx(windowHandle, 0, "NetUIHWND", vbNullString)
End If
If windowHandle <> 0 Then
'同じクラス名のウィンドウハンドルが2つ存在するので2回ループして取得する
Dim sameLevelWindowHandle As Long
sameLevelWindowHandle = 0
For i = 0 To 1 Step 1
sameLevelWindowHandle = WindowsUtility.FindWindowEx(windowHandle, sameLevelWindowHandle, "NetUICtrlNotifySink", vbNullString)
If sameLevelWindowHandle <> 0 Then
'ここでやっとページ番号部分のハンドルを取得
Dim pageNoHandle As Long
pageNoHandle = WindowsUtility.FindWindowEx(sameLevelWindowHandle, 0, "RICHEDIT60W", vbNullString)
If pageNoHandle <> 0 Then
'メッセージを送信する
Dim strWindowText As String * 10 'キャプションを受け取る変数
Dim pageNoCount As Integer
pageNoCount = GetWindowText(pageNoHandle, strWindowText, Len(strWindowText))
'Nullを除去した文字列とタイトルを比較する
If Left$(strWindowText, InStr(strWindowText, vbNullChar) - 1) = "1" Then
'タイトルを書き換える
Dim result As Integer
result = SetWindowText(pageNoHandle, "3")
If result <> 0 Then
'ページ番号の書き換えに成功
'ENTERキーを送信
Dim lngTemp1 As Long
Dim lngTemp2 As Long
Dim lngReturn As Long
lngTemp1 = WindowsUtility.MapVirtualKey(vbKeyReturn, 0&)
lngTemp2 = WindowsUtility.MakeDWord(1, CInt(lngTemp1))
lngReturn = WindowsUtility.PostMessage(pageNoHandle, WindowsUtility.WM_KEYDOWN, 13, lngTemp2)
End If
Exit For
End If
End If
End If
Next
End If
End Sub
流れとしては簡単で、以下になります。
- レポートのウィンドウハンドルを探す
- 配下のページ番号表示エリアのウィンドウハンドルを探す
- ページ番号の書き換えメッセージを送信する
- ENTERキー押下メッセージを送信する
レポートのウィンドウハンドルを探す
Accessレポートのウィンドウハンドルのクラス名はOReportPopup
です。
このウィンドウハンドルを検索します。
Dim windowHandle As Long
windowHandle = WindowsUtility.FindWindow("OReportPopup", vbNullString) 'レポートのハンドルを取得
配下のページ番号表示エリアのウィンドウハンドルを探す
あとはひたすらページ番号表示エリアのウィンドウハンドルを探すのを繰り返します。
'配下のページ番号部分のハンドルを取得
If windowHandle <> 0 Then
windowHandle = WindowsUtility.FindWindowEx(windowHandle, 0, "OSUI", vbNullString)
End If
If windowHandle <> 0 Then
windowHandle = WindowsUtility.FindWindowEx(windowHandle, 0, "NetUINativeHWNDHost", vbNullString)
End If
If windowHandle <> 0 Then
windowHandle = WindowsUtility.FindWindowEx(windowHandle, 0, "NetUIHWND", vbNullString)
End If
If windowHandle <> 0 Then
'同じクラス名のウィンドウハンドルが2つ存在するので2回ループして取得する
Dim sameLevelWindowHandle As Long
sameLevelWindowHandle = 0
For i = 0 To 1 Step 1
sameLevelWindowHandle = WindowsUtility.FindWindowEx(windowHandle, sameLevelWindowHandle, "NetUICtrlNotifySink", vbNullString)
If sameLevelWindowHandle <> 0 Then
'ここでやっとページ番号部分のハンドルを取得
Dim pageNoHandle As Long
pageNoHandle = WindowsUtility.FindWindowEx(sameLevelWindowHandle, 0, "RICHEDIT60W", vbNullString)
------------------------------------- 省略 -------------------------------------
End If
Next
End If
途中でループしているのはNetUICtrlNotifySink
というクラス名のハンドルが2つあるため、どちらに存在するかチェックするためです。
また、RICHEDIT60W
も2つ存在するため、以下のようにメッセージを送信してページ番号が1かどうか判定してチェックしています。
If pageNoHandle <> 0 Then
'メッセージを送信する
Dim strWindowText As String * 10 'キャプションを受け取る変数
Dim pageNoCount As Integer
pageNoCount = GetWindowText(pageNoHandle, strWindowText, Len(strWindowText))
'Nullを除去した文字列とタイトルを比較する
If Left$(strWindowText, InStr(strWindowText, vbNullChar) - 1) = "1" Then '1ページかどうか判定
------------------------------------- 省略 -------------------------------------
End If
End If
ここまでで対象のウィンドウハンドルが見つかったのであとは簡単です。
ページ番号の書き換えメッセージを送信する
ページ番号を書き換えるメッセージを送信します。
今回は3を指定しています。
'タイトルを書き換える
Dim result As Integer
result = SetWindowText(pageNoHandle, "3")
ENTERキー押下メッセージを送信する
最後にENTERキー押下メッセージを送信します。
これはポップアップなしと同じではうまくいきませんでしたので、別方法になっています。
If result <> 0 Then
'ページ番号の書き換えに成功
'ENTERキーを送信
Dim lngTemp1 As Long
Dim lngTemp2 As Long
Dim lngReturn As Long
lngTemp1 = WindowsUtility.MapVirtualKey(vbKeyReturn, 0&)
lngTemp2 = WindowsUtility.MakeDWord(1, CInt(lngTemp1))
lngReturn = WindowsUtility.PostMessage(pageNoHandle, WindowsUtility.WM_KEYDOWN, 13, lngTemp2)
End If
レポート起動
ここまでできたところで、レポートを起動します。
DoCmd.OpenReport "レポート名", acViewPreview
DoCmd.RunCommand acCmdZoom75 '
DoCmd.MoveSize 1000, 500, 24000, 15000
WindowsUtility.ReportMovePage
以上で、指定ページにレポートが切り替わります。
諸々修正してもらえれば、ポップアップなしの方もこれで実現できると思います。
参考
ウィンドウハンドルって?
Windowsのウィンドウに振られている一意なIDと認識しています。
・ウィンドウハンドル
ウィンドウハンドルのクラス名を知るには?
結局これがわからないと今回のことは実現できません。
今回の場合、Spy++というツールを使用しました。Visual Studioの付属ツールです。
このツールを起動すると、画面上のすべてのウィンドウハンドルの情報が詳細に見ることができます。
私の場合業務でVisual Studioを使用していたため普通に使用できましたが、無料で使用できるかどうかまでは不明です。
検索等で入手方法を調べていただければと思います。