投稿者 魔界の仮面弁士  (社会人) 投稿日時 2021/12/30 10:52:51
> 御教授頂いた所などを直しましたら、エラーを再現できなくなりました。
> 何十万件でも大丈夫なようでした。
改善されたようで良かったです!

気になる点を指摘しただけのあてずっぽう回答でしたが、
結局何が原因だったのか…ブラシ指定漏れですかね?
http://www.tt.rim.or.jp/~rudyard/torii009.html

> Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, ByVal 0&, MyBMPInf, 0)
> ReDim MyBMPBits(MyBMPInf.bmiHeader.biSizeImage - 1)
> Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, MyBMPBits(0), MyBMPInf, 0)
その表記が許されるのは VBA6 まであり、VBA7 では NG です。

GetDIBits の「LPVOID lpvBits」引数の Declare 宣言を
現状は ByRef lpBits As Any と翻訳しているようなので
 #If Win64
  Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, ByVal 0^, MyBMPInf, 0)
 #Else
  Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, ByVal 0&, MyBMPInf, 0)
 #End If
 ReDim MyBMPBits(MyBMPInf.bmiHeader.biSizeImage - 1)
 Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, MyBMPBits(0), MyBMPInf, 0)
と書くのが正しいです。LongPtr 型を示す型宣言文字は存在しないため、
bit 数に応じて LongLong リテラルと Long リテラルを使い分けます。

とはいえ、#If ディレクティブを使うのも煩わしいでしょうから、
 'Win32 では As Long = 0& 相当、Win64 では As LongLong = 0^ 相当の定数
 Const NullPtr As LongPtr = 0
をあらかじめ用意しておいて、それを用いて
 Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, ByVal NullPtr, MyBMPInf, 0)
のように呼ぶ方が簡単かと思います。

あるいは別案として、『ByRef lpBits As Any』を『ByVal lpBits As LongPtr』に変更して
 Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, 0, MyBMPInf, 0)
 ReDim MyBMPBits(MyBMPInf.bmiHeader.biSizeImage - 1)
 Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, VarPtr(MyBMPBits(0)), MyBMPInf, 0)
のように呼び出すのもありです。

もしくはバイナリ指定用の「ByRef lpBits As Byte」版と
NULL 指定用の「ByVal lpBits As LongPtr」版の 2 種類の宣言を Alias 指定して
 Call GetDIBitsNull(MyDC1, MyBMP, 0, CHEIGHT, 0, MyBMPInf, 0)
 ReDim MyBMPBits(MyBMPInf.bmiHeader.biSizeImage - 1)
 Call GetDIBitsByte(MyDC1, MyBMP, 0, CHEIGHT, MyBMPBits(0), MyBMPInf, 0)
などと使い分ける手法もあります。


Office 2016 以降では 64bit 環境が主流となっていますが、ネット上にあるサンプルは
32bit 時代のコードがまだまだ多いですし、VBA7 版でも Win64 対応が不十分なサンプルが
出回っていたりしますので、注意が必要ですね。


そして、似て非なる状況なのがこちら。

> MyDC0 = GetDC(0&)
> Call ReleaseDC(0&, MyDC0)
これも同様に、Win64 環境の場合は 0^ 、Win32 環境の場合は 0& を渡すべきなのですが、
こちらは Any ではなく、『ByVal h As LongPtr』な引数として Declare されていますので、
この場合は暗黙の型変換にお任せして、「0」表記でも「0&」表記でも大丈夫です。私は 0 派です。

極端な話、ここに「"0"」や「0.0」を渡したとしても正常に動作します。
(それが良いコードかどうかは別として!)

ちなみに、ハンドル(HDC とか HWND とか)というデータ型は、
Win32 では 32bit、Win64 では 64bit サイズではありますが、
互換性上の都合から、Win64 でも実際には下位 32bit 部しか
使われていなかったりします。ポインタとハンドルの違いというやつですね。

さらに丁寧に書くなら、Office 2007 以下にも配慮して、#If VBA7 Then ディレクティブを
併用することになりますが…2003 や 2007 等で動かすことが無い場合は冗長になりますね。