honjarake blog

自分用にテキトーにまとめる

Access レポート プレビューか印刷か判別

APIを使わずに」判別する方法
以下、引用元のサイトが閉鎖しているのでWeb Archiveから
印刷かプレビューか、それが問題だ | YU-TANG's MS-Access Discovery

  • レポートの [アクティブ時] イベントが発生しなかったら、それは印刷である。
  • レポートの [アクティブ時] イベントが発生したら、それは印刷プレビューである。
  • ただし、[Visible] プロパティが True だったら、それは印刷プレビューからの印刷である。

これを利用して、レポートがプレビューモードで表示されているのか、それとも実際に印刷されているのかを判断し、それぞれの状況に応じた異なる処理を実行するというもの。


>コードの引用(クリックで表示)

判定をCloseなどに記述すると「プレビューしただけのとき」と「印刷したとき」で処理を変えられた。
「印刷したときだけ該当帳票の印刷済フラグをON」にするという用途に使用。
2025年7月時点のMicrosoft365版でも、特殊な処理をしていないレポートで十分に判別できる。

実行ファイルからアイコンを抽出するPoweshellスクリプト

生成AIの補助で実行ファイルからアイコンを抽出するPower Shell スクリプトを作ったので記録

# 必要なアセンブリを明示的に参照します。
# System.Drawing と System.Windows.Forms はGUI関連のクラスを提供するために必要です。
Add-Type -TypeDefinition @"
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms; // System.Windows.Forms アセンブリへの参照が必要

public class IconExtractor
{
    // Shell32.dll から ExtractIconExW 関数をインポートします。
    // この関数は、指定されたファイルからアイコンを抽出するために使用されます。
    [DllImport("Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern uint ExtractIconEx(
        string lpszFile,     // アイコンを抽出するファイルのパス
        int nIconIndex,      // 抽出するアイコンのインデックス (-1 はアイコンの総数を取得)
        out IntPtr phiconLarge, // 大きいアイコンのハンドルを受け取るポインタ
        out IntPtr phiconSmall, // 小さいアイコンのハンドルを受け取るポインタ
        uint nIcons          // 抽出するアイコンの数 (0 はアイコンの総数を取得)
    );

    // user32.dll から DestroyIcon 関数をインポートします。
    // この関数は、アイコンハンドルによって占有されているリソースを解放するために使用されます。
    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool DestroyIcon(IntPtr hIcon);

    /// <summary>
    /// 指定されたファイルからすべてのアイコンを抽出します。
    /// </summary>
    /// <param name="filePath">アイコンを抽出する実行可能ファイルまたはDLLファイルのパス。</param>
    /// <returns>抽出されたIconオブジェクトの配列。アイコンが見つからない場合は空の配列。</returns>
    public static Icon[] ExtractAllIcons(string filePath)
    {
        // out パラメータを事前に宣言することで、古いC#コンパイラとの互換性を確保します。
        IntPtr phiconLargeDummy;
        IntPtr phiconSmallDummy;

        // まず、EXEファイル内のアイコンの総数を取得します。
        // -1 をnIconIndexに指定し、nIconsに0を指定することで、アイコンの数を取得できます。
        uint totalIcons = ExtractIconEx(filePath, -1, out phiconLargeDummy, out phiconSmallDummy, 0);

        if (totalIcons == 0)
        {
            // アイコンが見つからないか、エラーが発生した場合
            return new Icon[0];
        }

        Icon[] icons = new Icon[totalIcons];
        for (int i = 0; i < totalIcons; i++)
        {
            // 各アイコンの抽出時に使用するoutパラメータをループ内で宣言します。
            IntPtr phiconLarge;
            IntPtr phiconSmall;

            // 指定されたインデックスのアイコンを抽出します。
            // 最後の引数 (nIcons) を 1 にすることで、1つのアイコンのみを抽出するように指示します。
            ExtractIconEx(filePath, i, out phiconLarge, out phiconSmall, 1);

            // 大きいアイコンのハンドルが有効な場合、それを使用します。
            if (phiconLarge != IntPtr.Zero)
            {
                icons[i] = Icon.FromHandle(phiconLarge);
                // Icon オブジェクトはハンドルを所有するため、ここで DestroyIcon を呼び出す必要はありません。
                // Icon オブジェクトがDisposeされるときに解放されます。
            }
            // 大きいアイコンがないが、小さいアイコンのハンドルが有効な場合、それを使用します。
            else if (phiconSmall != IntPtr.Zero)
            {
                icons[i] = Icon.FromHandle(phiconSmall);
                // 同上
            }
        }
        return icons;
    }
}
"@ -ReferencedAssemblies "System.Drawing.dll", "System.Windows.Forms.dll"

# --- 設定 ---
# ここをアイコンを抽出したいEXEファイルのパスに置き換えてください。
$exePath = "C:\Program Files (x86)\hogehoge\hoge.EXE" 

# アイコンを保存するディレクトリ。ユーザーのデスクトップに"ExtractedIcons"を作成します。
$outputDir = Join-Path $env:UserProfile\Desktop "ExtractedIcons" 

# 出力ディレクトリが存在しない場合は作成
if (-not (Test-Path $outputDir)) {
    Write-Host "Output directory '$outputDir' does not exist. Creating it now."
    New-Item -ItemType Directory -Path $outputDir | Out-Null
}

# --- 処理 ---
try {
    Write-Host "Searching for icons in: $exePath"

    # IconExtractor クラスを使用してアイコンを抽出します。
    $icons = [IconExtractor]::ExtractAllIcons($exePath)

    if ($icons.Length -eq 0) {
        Write-Warning "No icons found in '$exePath' or an error occurred."
    } else {
        Write-Host "Found $($icons.Length) icons. Saving to '$outputDir'..."
        for ($i = 0; $i -lt $icons.Length; $i++) {
            $icon = $icons[$i]
            # EXEファイル名から拡張子を除いた部分を取得します。
            $baseFileName = [System.IO.Path]::GetFileNameWithoutExtension($exePath)
            # アイコンごとに連番を付けてファイル名を生成します。例: ACCICONS-1.bmp
            $outputFileName = "$baseFileName-$($i+1).bmp" 
            # 出力ファイルの完全パスを作成します。
            $outputPath = Join-Path $outputDir $outputFileName

            # IconオブジェクトをBitmapに変換し、BMP形式で保存します。
            $icon.ToBitmap().Save($outputPath, [System.Drawing.Imaging.ImageFormat]::Bmp)
            Write-Host "Saved: $outputPath"

            # Iconオブジェクトが保持するリソースを解放します。これは非常に重要です。
            # 各アイコン処理後にDisposeすることで、メモリリークを防ぎます。
            $icon.Dispose()
        }
        Write-Host "All icons extracted and saved successfully."
    }
} catch {
    # エラーが発生した場合、エラーメッセージを表示します。
    Write-Error "An error occurred: $($_.Exception.Message)"
}

条件付き書式を複数コントロールに使用した画面のちらつきの解決

Accessのフォーム処理(Form_Open や検索時の RowSource / Filter 変更)で、内部処理は完了しているのに画面の点滅や読み込み中カーソルが消えない現象が発生する。
マウスを動かせば解消するが、ユーザーが読み込み中と勘違いして待機してしまうため、対策を行った。

一般的な対策とその限界

以下の描画停止・再開処理を試したが、マウスがコントロールの上にあるとチラつきが残る問題があった。

' 一般的な対処法例
Me.Painting = False ' 描画停止
' (または Application.ScreenUpdating = False / DoCmd.Echo False)
' --- ここで Filter や RowSource の書き換え処理 ---
Me.Painting = True  ' 描画再開
' (または Application.ScreenUpdating = True / DoCmd.Echo True)

解決策

処理の最後に Me.Recalc を実行する。

' 例
Me.Painting = False
' --- 検索・RowSource等の変更処理 ---
Me.Painting = True

Me.Recalc ' ← これを追加するとチラつき(読み込み)が収まる

考察・補足

Me.Refresh や Me.Requery はバージョンによって効果なし。
本来は Me.Repaint で解消しそうなものだが、なぜか Me.Recalc(再計算)のみが効く。
Me.Recalc は描画再開処理の前後どちらに配置しても動作した。

SQL ServerのDB カラム型と AccessDB フィールド型 データ競合エラー関係

現象:
チェックボックス用にSQL Serverでbit型のカラムAを追加、初期値を0になるように設定(DEFAULT (0) FOR カラムA)
→カラムA追加時点ではすべてNULLの状態
AccessクライアントでカラムAをコントロールソースとするチェックボックスを作成
Accessでのフィールドの型はYes/No型)

・フォームでこのチェックボックスをONにすると、必ずデータの競合エラーになる

原因:
・Yes/No型のフィールドがNULLの時、チェックボックスをOn/off(Yes/No)変更すると必ず競合エラーになる

解決策:
・先に全てのNULLを解消する→SQL Serverなら カラムA=0 か カラムA=1で更新(Update)する
・DEFAULT (0) FOR カラムA を すべてのNULL更新後に行う
または
SQL Server側をsmallint型 NULL許容にする(True=-1 False=0)として扱われる

未確認:SQL Server側をtinyint型にする→AccessではByte型になる。Byte型だと挙動が異なる?

自分用 Microsoft Office C2R版のバージョン戻し

一番参考になったサイト:
prau-pc.jp

cd %programfiles%\Common Files\Microsoft Shared\ClickToRun
OfficeC2RClient.exe /update user updatetoversion=16.0.xxxx.yyyy

上記をバッチファイルとしてサーバーに保存し、ショートカットで各PCに貼り付け
プロパティの詳細設定で管理者として実行とでもしておくと少し楽かと思った。

今回、自作の「管理者権限で実行するexe」を間に挟んだら普通に管理者権限で起動するつもり。
ADならグループポリシー使えばもっと楽なのだろうか。


あとは、バージョン戻した後に、問題のあったバージョンに勝手に更新されないよう
修正版がくるまでOfficeの更新は切っておくこと。

Outlook で 「今後このメッセージを表示しない」にチェック入れてしまったとき

受信拒否リストではなく、SharePointと連動しているメールボックスサイト メールボックス?通知メール?→「SharePointリスト」)の
メッセージを消すのに1件1件削除確認されるのでチェックしたら、二度と表示されなくなった。
Outlookのオプションからは元に戻せない。

解決方法:レジストリをいじる

HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Outlook\Options\General
以下にある
PONT_STRING
Value Data 35 を削除してください。

値は「52,」が入っていたので、空にすると確認メッセージ表示されるようになった。
引用元に載っているように、対応する番号とカンマを削れば
再表示したいメッセージだけ戻せるのかもしれない。
→引用元に書いてあるサイト(Web Archive):Outlook "Don't Show Again" dialog settings

自分用 OFFICE2007以降 VBA FileSearchについて

pocket9 ドキュメント支援ツール
機能一覧 | 設計書仕様書テンプレート PocketDOC | 株式会社イーイノベーション
の「PocketDocPropertyChangeTool」を利用しようとしてFileSearchでエラーが出た。
調べてみると、Application.FileSearchの構文がOFFICE2007以降で使えなくなっているとの事。

FileSearchをScripting.FileSystemObjectのFileSearchに入れ替えれば動くようなので
クラス化している下記のサイト
Office2007以降廃止となった「FileSearch」の代替クラスを作る - xixiixiiixivの勉強日記
を見つけてそのまま置き換えてみた。
※上記ソースコードをVBEでクラスモジュールとして貼付し、FileSearchClassという名前で保存。

PocketDocPropertyChangeTool側の記述を変更していく。

<shtMain>
[Private Sub cmdAction_Click]
 ' ファイル検索の開始
'   With Application.FileSearch
    With New FileSearchClass

おまけでBrowseForFolderに初期値表示のフォルダを設定

<shtMain>
[Private Sub cmdAction_Click]
 CreateObject("Shell.Application").BrowseForFolder(0, "フォルダを選択してください", &H1 + &H10, vDefFolder)

上記のvDefFolderの部分の引数はVariant型でないと初期値として反映されず少し詰まった。(ずっとString型で指定していた)

ここまでの修正を実行するとFileSearchClassにFileTypeのプロパティがなくてエラーが発生。

<shtMain>
[Private Sub cmdAction_Click]
.FileType = msoFileTypeAllFiles

消してもいいけど、後で処理を追加してみようと思い、クラスにダミーのFileTypeを追加。

端末毎に参照設定いじるのめんどそうだなと思い
FileSearchClass側の fso関連の変数を全部Objectに変更して
new FileSystemObject してるところを CreateObject("Scripting.FileSystemObject") に置き換えた。
FileTypeはmsoFileTypeが使えればそのまま使うが、下記のようにした。

<FileSearchClass>
Public Enum enumFileType
  msoFileTypeAllFiles = 1
  msoFileTypeBinders = 6
  msoFileTypeCalendarItem = 11
  msoFileTypeContactItem = 12
  msoFileTypeDatabases = 7
  msoFileTypeDataConnectionFiles = 17
  msoFileTypeDesignerFiles = 22
  msoFileTypeDocumentImagingFiles = 20
  msoFileTypeExcelWorkbooks = 4
  msoFileTypeJournalItem = 14
  msoFileTypeMailItem = 10
  msoFileTypeNoteItem = 13
  msoFileTypeOfficeFiles = 2
  msoFileTypeOutlookItems = 9
  msoFileTypePhotoDrawFiles = 16
  msoFileTypePowerPointPresentations = 5
  msoFileTypeProjectFiles = 19
  msoFileTypePublisherFiles = 18
  msoFileTypeTaskItem = 15
  msoFileTypeTemplates = 8
  msoFileTypeVisioFiles = 21
  msoFileTypeWebPages = 23
  msoFileTypeWordDocuments = 3
  msoLastModifiedAnyTime = 7
  msoLastModifiedLastMonth = 5
  msoLastModifiedLastWeek = 3
  msoLastModifiedThisMonth = 6
  msoLastModifiedThisWeek = 4
  msoLastModifiedToday = 2
  msoLastModifiedYesterday = 1
End Enum

FileSearchClass の方に下記を追加

<FileSearchClass>
Public FileType As enumFileType

shtMainも変更

<shtMain>
[Private Sub cmdAction_Click]
' .FileType = msoFileTypeAllFiles     '検索対象ファイルのタイプを設定
  .FileType = enumFileType.msoFileTypeAllFiles

また、ここまでの修正で

<shtMain>
[Private Sub cmdAction_Click]
.FileName = "*.xls;*.doc;"

の複数拡張子指定で、一切一致するファイルを見つけられなかった。
Likeでも書き方次第で判定できそうだが、正規表現でのマッチングに変更した。

FileSerchClassに下記を追加

<FileSearchClass>
'正規表現マッチング
Private Function ExtRegExp(ByVal Target As String, ByVal FileExt As String) As Boolean
  'RegExpオブジェクトの作成
  Dim reg As Object
  Set reg = CreateObject("VBScript.RegExp")
  
  Dim sPtn As String
  
  'パターン作成
  sPtn = Replace(FileExt, " ", "")
  sPtn = Replace(sPtn, "*.", "")
  sPtn = Replace(sPtn, ";", "|")
  sPtn = IIf(sPtn Like "*|", Left(sPtn, Len(sPtn) - 1), sPtn) '末尾条件整理
  sPtn = ".+\.(" & sPtn & ")"                                 '「*.(拡張子1[|拡張子2]...)」に成形
  
  '正規表現の指定
  With reg
      .Pattern = sPtn     'パターンを指定
      .IgnoreCase = True  '大文字と小文字を区別するか(False)、しないか(True)
      .Global = True      '文字列全体を検索するか(True)、しないか(False)
  End With

  ExtRegExp = (reg.Execute(Target).Count > 0)

End Function

Likeで拡張子の判定している箇所をExtRegExpに置換

<FileSearchClass>
[Private Sub runSearch(sArgSearchPath As String)]
' If Not (oFile.Name Like FileName) Then GoTo CONTINUE ' 処理対象外を除外
 If Not ExtRegExp(oFile.Name, FileName) Then GoTo CONTINUE  ' 処理対象外を除外

これで大体動くようになった。