BricsCAD VBAを使ってみよう[4] VBAの基本コード①

前回の
BricsCAD VBAを使ってみよう[3] UserFormその2
からの続篇です。

VBAの検討を進めていくときに参考として、①マクロVBAの構成と②BricsCADのコマンドの構文を、そのつどあれこれ調べるのも時間がかかりますので、忘備録で順次こちらに残してくようにします。(時間が経つとけっこういろいろと忘れますので)

1,VBマクロの構成

1,各モジュールへのプロシージャの配置

VBマクロのコード記述場所

ThisDrawing内のコードはこの図面内でのクラスモジュール
ユーザーフォームはフォームモジュールを使用
汎用的な活用では標準モジュールを使用

2,メインルーチンとサブルーチン

モジュール内で実行する(メインルーチンの)プロシージャ内で、一度に長いプログラムを作成すると、プログラムの「可読性」が低くなり、バグが混入しやすくなり、バグの原因特定やバグフィックスに時間が掛かる原因になります。

「可読性」を高くする一つの手段として、サブルーチン化して、そのプロシージャを呼び出すCallステートメントを使用します。呼び出す側のメインルーチンと対比してサブルーチンと呼ばれます。

次のコード例では、test_2とtest_3はtest_1に呼び出されるサブルーチンです。

サブルーチンのプロシージャは、Private Sub・・・としておくと、マクロの一覧には表示されません。

Option Explicit

Dim sBuf As String

Sub test_1()

    Call test_2
    Call test_3

End Sub

Private Sub test_2()

    sBuf = "テスト2"
    MsgBox (sBuf)

End Sub

Private Sub test_3()

    sBuf = "テスト3"
    MsgBox (sBuf)

End Sub

3,プロシージャ間のスコープ

Publicで宣言したプロシージャはすべてのモジュール間で有効となります。
Moduleを分けて、別のModuleからFunctionプロシージャを呼び出せます。

他の作成したVBAマクロで、共通の処理が行えるプロシージャを使いまわしができるようになります。

Option Explicit

Sub test_4()

    Dim txt As String
    
    txt = "テスト4"
    
    MsgBox (addtxt(txt))

End Sub

Option Explicit

Public Function addtxt(txt As String) As String

    addtxt = txt & "を確認しました"
    
End Function

 

2,変数の型

 

データ型 変数の範囲
Byte バイト型 0~255の範囲の単精度の正の数値
Long 長整数型 -2,147,483,648 ~ 2,147,483,647
Single 単精度浮動小数点数型 -3.402823E38 から -1.401298E-45 (負の値)
1.401298E-45 から 3.402823E38 (正の値)
Double 倍精度浮動小数点数型 -1.79769313486231E308 から -4.94065645841247E-324 (負の値)4.94065645841247E-324 から 1.79769313486232E308 (正の値)
String 文字列型 0 〜 約 20 億
Boolean ブール型 真 (True) または偽 (False)
Object オブジェクト型 オブジェクト
Variant バリアント型 すべてのデータ

上記以外その他の変数型もありますが、
主に使用するデーター型
整数:Long
小数:Double
文字列:String
真・偽:Boolean
配列、オブジェクト Variant

変数はDim
Dim “変数名” As “データー型”
定数はConst
Const “変数名” As “データー”=”値”

3,プロシージャ間の「値渡し」と「参照渡し」

プロシージャが持つ値に、「変数」「定数」「式」がありますが、通常は「変数」を引き渡します。

引き渡す値に「値渡し:ByVal」と「参照渡し:ByRef」があります。

Option Explicit

Dim Cnt As Integer

Sub test_9()

    Cnt = 1
    
    Call test_10(Cnt)
    
    MsgBox (Cnt)
    
End Sub


''Private Sub test_10(ByVal Cnt As Integer)
Private Sub test_10(ByRef Cnt As Integer)

    Cnt = Cnt + 1
    
End Sub


Sub test_10の、CntでMsgBox (Cnt)は、

ByVal の場合・・・・1

ByRef の場合・・・・1+1で2

となります

数字だけでなく文字列でも同様です。

ByValを指定すると値が渡され、ByRefを指定すると(処理後の)参照が渡されます。

 

・・・それほど複雑な大きなプログラムは組みませんので、subプロシージャ間でやり取りする程度では(無いとエラーになる場合を除いて)特には気にしません。しかし関数のFunctionプロシージャは、内部で引数で処理して戻り値を渡す作業を行いますので注意が必要です。

 

Function プロシージャ名(引数 As データ型) As 戻り値のデータ型
プロシージャ名=戻り値
End Function

戻り値がなかったり、引数がなかったり引数が複数の場合があります。

 

変数に関しては、まだ記載しておきたいこともありますが、以降の検討中に記載するようにします。

 

検討していたお題で面白そうなテーマで・・・

4,キーボードのイベントを取得するsubプロシージャ

テンキー入力のイベントを取得し作図するコード例

このコード例では、テンキー入力のイベントを取得する、GetAsyncKeyState関数を使用しています。

例えば、
If GetAsyncKeyState(vbKeyNumpad0) Then・・・・で、
テンキーの0が押されているか、押されたを示す値が返ります。

【テンキー入力 → 挿入点クリック → 指示した数の同心円を描画】

Option Explicit

'Win32API宣言(64bit)
'キー情報関数
Declare PtrSafe Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer

Dim keynum As Long

Sub GetTenKey()

Dim Pt() As Double

keynum = 0

On Error Resume Next

 ''図形挿入基準点を指示
    Pt = ThisDrawing.Utility.GetPoint(, "テンキー入力:挿入点をクリック ")
    
       Call Getkeynum
       
        ''キャンセルの場合
        If Err Then
            ''エラー処理を戻す
            On Error GoTo 0
            Exit Sub
        End If
        
        ''MsgBox (keynum)
        
        Dim myCircle As AcadCircle
        Dim dHeight As Double
        dHeight = 100
        Set myCircle = ThisDrawing.ModelSpace.AddCircle(Pt, dHeight)
        
        Dim offsetObj As Variant
        Dim i As Byte
        ''円の間隔を文字高さの1/10にする
        For i = 1 To keynum
        offsetObj = myCircle.Offset(dHeight / 10 * i)
        Next
        '作図図形範囲にZoom
        ThisDrawing.Application.ZoomExtents
        '図面を更新
        ThisDrawing.Application.Update


End Sub

Private Sub Getkeynum()

        If GetAsyncKeyState(vbKeyNumpad0) Then
            keynum = 0
        ElseIf GetAsyncKeyState(vbKeyNumpad1) Then
            keynum = 1
        ElseIf GetAsyncKeyState(vbKeyNumpad2) Then
            keynum = 2
        ElseIf GetAsyncKeyState(vbKeyNumpad3) Then
            keynum = 3
        ElseIf GetAsyncKeyState(vbKeyNumpad4) Then
            keynum = 4
        ElseIf GetAsyncKeyState(vbKeyNumpad5) Then
            keynum = 5
        ElseIf GetAsyncKeyState(vbKeyNumpad6) Then
            keynum = 6
        ElseIf GetAsyncKeyState(vbKeyNumpad7) Then
            keynum = 7
        ElseIf GetAsyncKeyState(vbKeyNumpad8) Then
            keynum = 8
        ElseIf GetAsyncKeyState(vbKeyNumpad9) Then
            keynum = 9
        End If

End Sub

 

実行直後に、先にテンキーで追加する繰り返し描画回数を指示します。画面をクリックすると同心円を描きます。

ここではテンキーで追加する円の数を決めて描きますが、テンキーだけでなくほかのキーも使え、その他何らかの処理をするのに面白そうです。

 

5,Functionで「ByVal」と「ByRef」使用の例

前述の「値渡し:ByVal」と「参照渡し:ByRef」の参考コードです。

2点をクリックしてその間隔を計測します。

Option Explicit

Sub Get2PointsDistance()

Dim gp1 As Variant, gp2 As Variant

On Error Resume Next

    Do
        gp1 = ThisDrawing.Utility.GetPoint(, "1点目をクリック : ESCで終了 ")
        'キャンセルの場合
            If Err Then
                On Error GoTo 0
                Exit Sub
         End If
        gp2 = ThisDrawing.Utility.GetPoint(, "2点目をクリック: ")

        MsgBox ("2点間は " & Calcdist(gp1, gp2) & " ㎜です")
        
    Loop

End Sub

Function Calcdist(ByRef gp1 As Variant, ByRef gp2 As Variant) As Double

    Dim x As Double, y As Double, z As Double
    x = gp1(0) - gp2(0): y = gp1(1) - gp2(1): z = gp1(2) - gp2(2)
    Calcdist = Sqr((Sqr((x ^ 2) + (y ^ 2)) ^ 2) + (z ^ 2))

End Function

でも・・・実は、CAD本体のVBAでひらえるんです。。。
まぁ、それはそれ、これはこれとして。。。

Option Explicit

Sub Get2PointsDistance()

    Dim Distance As Double
    Distance = ThisDrawing.Utility.GetDistance(, "2点をクリックして計測")
    MsgBox "2点間は " & Distance & " ㎜です"
    
End Sub

 

6,Win32API関数

Windows APIはWindowsの各機能にアクセスするための機能を提供します。

上記の例で、テンキー入力を取得・コード実行を一時中断していますが、その他多種多様な機能の関数があり、VBAの動作の幅を広げることにとても有用です。

使用するうえでの注意点として、VBAのバージョンで記述が異なることです。
MSOffice2007以前では、VBA 6.x用の記述(32bit)
MSOffice2010以降では、VBA 7.x 用の記述(32bit/64bit両対応)
(現在使用中のMSOffice2019でもVBA 7.1ですね)

VBA 7.x 用の記述リファレンスの参考資料として、Microsoft公式のもので下記のヘルプファイルがダウンロードできます。

Micrsoft ダウンロードセンター

「Office 2010 Help Files: Win32API_PtrSafe with 64-bit Support」
の下の赤いボタンをクリックしてダウンロード
ダウンローされたSitemapCreator5Setup.exeをダブルクリック
Cドライブ直下に解凍されます。
→Office 2010 Developer Resourcesフォルダー
→Documentsフォルダー
→Office2010Win32API_PtrSafeフォルダー内に
以下のファイルがあります。

VBA 7.x 用の記述は、解凍したファイルの中の「Win32API_PtrSafe.TXT」内に記載されています。(テキストファイルをPDFにして検索して使っています。)

GetAsyncKeyStateを検索すると、

と出てきます。

上記のコードです。
Declare PtrSafe Function GetAsyncKeyState Lib “user32” Alias “GetAsyncKeyState”(ByVal vKey As Long) As Integer

VBEのコードウインドウにこのコードを張り付けると・・・・

Declare PtrSafe Function GetAsyncKeyState Lib “user32” (ByVal vKey As Long) As Integer
になります。(のでそのまま使っています。)

たぶん、なんだぁ同じ名前じゃないかぁ~!とおこられてるんですね。

 

呼び出し宣言の書式

Declare PtrSafe Function 関数名 Lib “DLL名” AliasAPI名” (引数…) As 戻り値の型

PtrSafe キーワード(64bitVBAにコンパイルする)
DeclareステートメントにはPtrSafeキーワードを含める必要があります。 PtrSafe キーワードは、Declare ステートメントを 64 ビットの開発環境で安全に実行できることを示すキーワードです。
関数名
基本的にC言語で宣言されたAPIと同じものを使用します。
Lib キーワード
Libの後に、呼び出す関数を含む DLL の名前と場所を指定します。
Alias キーワード
API名がDLLの中では別の名前で公開されている場合は、Alias 節で公開されている関数名を宣言します。

例えばウィンドウのキャプションタイトルを取得するAPIは

Declare PtrSafe Function GetWindowText Lib “user32” _
Alias “GetWindowTextA” (ByVal hwnd As Long, _
ByVal lpString As String, ByVal cch As Long) As LongPtr

となります。

ウインドウ関係のAPIでは、Alias が使われています。

アドレス参照(ポインターおよびハンドルを格納する場合) の引数は、32Bit版では、Long型ですが、64Bit版では、LongPtr型 または Longlong型になる・・・とのことらしいです。。。

と、いろいろ調べながら進めています。

 

次ページでは、(すでにいろいろと使ってますが)繰り返し動作、分岐処理について検討しました。

 BricsCAD VBAを使ってみよう[5] VBAの基本コード②

 

coffee break

今回の件で、VBAでいろいろと考えている中で、Win32APIがVBAと共に使いこなせれば面白そうだなぁと思いました。テンキー以外でもスペースとか使えそうですね。

ちょっとした操作でも数があれば、少しでもさっと処理ができると、とてもメリットがあります。
またいろいろと調べて、ほかの機能も組み込んでいけるようにしたいです。

 

BricsCAD VBAを使ってみよう INDEX

BricsCAD VBAを使ってみよう[1] VBAのインストール

BricsCAD VBAを使ってみよう[2] UserFormその1
「BricsCAD VBA 」Creating UserForm

BricsCAD VBAを使ってみよう[3] UserFormその2
「BricsCAD VBA 」SerialNumber drawing with UserForm

BricsCAD VBAを使ってみよう[4] VBAの基本コード①

BricsCAD VBAを使ってみよう[5] VBAの基本コード②

BricsCAD VBAを使ってみよう[6] Excelとの連携①
「BricsCAD VBA to Excel」Get_CoordinateValues

BricsCAD VBAを使ってみよう[7] Excelとの連携② 
「Excel VBA to BricsCAD」Get_Area

BricsCAD VBAを使ってみよう[8] Excelとの連携②-2 
「Excel VBA to BricsCAD」Draw_ChannelSteel

BricsCAD VBAを使ってみよう[9] TABLEの自動作成と値入力
「BricsCAD VBA 」AutomaticCreation of TABLE

BricsCAD VBAを使ってみよう[10] Excelとの連携②-3
「Excel VBA to BricsCAD」SerialNumber_Ⅱ

BricsCAD VBAを使ってみよう[11] Excelとの連携②-4 
「Excel VBA to BricsCAD」Draw_Rectang

BricsCAD VBAを使ってみよう[12] Excelとの連携②-5 指定画層にOffset
「Excel VBA to BricsCAD」Continuous Offset to Specified Layer

BricsCAD VBAを使ってみよう[13] Excelとの連携②-6 指定画層にHATCH
「Excel VBA to BricsCAD」Continuous Hatch to Specified Layer

 

以下検討中です。

◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇
「この特集記事の内容につきましては、
こちらの環境のみの検討結果です。
動作保証は出来かねますため、ご参考
資料としてお扱いください。
Windows10(64bit)
BricsCAD pro V20(64bit)
Office2019(64bit)
◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇