C#ATIA

↑タイトル詐欺 主にFusion360API 偶にCATIA V5 VBA(絶賛ネタ切れ中)

オプションの設定を切り替える(発見手順)

最近こそ業務の依頼として頂くので、CATIAで2D図を使うようになったのですが
以前からあまり好きではなく、他の2DCADで構わないのであれば他のCADを
使っていました。その理由のひとつが(3Dから投影したもの以外の)線を
ドラッグした際動いちゃう事なんです。

でも、こちらのオプションの設定で固定できる事に気が付きました。
f:id:kandennti:20190301132908p:plain
あ~便利だ、と思ったものの人間はわがままです。ちょっとだけ動かしたいなぁ
と思うんです。その都度オプション開いてONにし動かした後にOFFにするのは
面倒です。(そもそも移動コマンドがもっとまともなら、気にしないのですが)


オプションの設定を知る方法のひとつが、CATSettingsファイルを見る事なのですが
バイナリファイルな為、エディタで開いてもわかりません。
その為、XMLフォーマットに変換する為のプログラムが存在しています。

ここに記載されている、CATBatGenXMLSetがそうです。
Importing and Exporting Settings Files to/from XML Format
インストールフォルダ内のCATIAの実行ファイルと同じフォルダに
入っているはずです。
(逆に XML→CATSettings はCATBatImpXMLSetです。)
でも、個人的な感覚としてCATSettingsファイルは、CATIA起動時に
読み込んで終了時に書き出しており、起動中のCATIAに対しては
何の役にも立たないんです。上記のオプションをマクロで変更したい時
CATSettingsを書き換えても変わってくれないはずです。


マクロの記録をとっても空、Webで検索してもHit無しなので
困って諦めていたのですが、Helpを見るとここにパラメータ値を
エクスポートするボタンがあると記載が有りました。
f:id:kandennti:20190301132942p:plain
エクスポートしてみると何と、catvbsファイルなんです。
これなら届きそうです。

1)変更したいオプションの変更前と変更後をエクスポート。
 上書きしてしまう為、一度行ったものをリネームして二度目を
 実行してください。

2)違いを比較。イロイロ方法はあると思うのですが、コマンドプロンプト
 を起動し、FCで比較しました。
f:id:kandennti:20190301132956p:plain
ネーミングからしてもパラメータ名 ”Drw_settings_DragElts” が
怪しそうなのです。
エディタで開いてみると
f:id:kandennti:20190301133031p:plain
まぁそうね、程度ですけど。

3)エクスポートしたcatvbsの先頭付近を参考にし、入力補完にも助けられ
こんな感じのコードを実行すると無事切り替わりました。

Sub CATMain()

    Dim setctl As SettingControllers
    Set setctl = CATIA.SettingControllers
    
    Dim setPpty As SettingRepository
    Set setPpty = setctl.Item("DraftingOptions")
    
    Dim bl As Boolean
    bl = IIf(setPpty.GetAttr("Drw_settings_DragElts"), _
            False, True)
    
    'キャストする必要有り
    Call setPpty.PutAttr("Drw_settings_DragElts", CBool(bl))

End Sub

試していないので断言できないのですが、今回の事を考えると
マクロでオプションの設定を知ることも変更する事も、
全て可能なのではないかと思います。今更かな?

Select Case True

覚書です。

'vba
Select Case True

知った際に結構衝撃的だったのですが、先にTrueを条件にしてしまい
イロイロと異なる条件を元に判断してしまうのに利用しています。
(雰囲気的にYesマンみたいなイメージです)

この記法は結構独特なのかと思っていたのですが、
C,C++,Java,Js等の switch(true) みたいな書き方はありそうです。
確かC#では確か出来なかったですし、Pythonではそもそも
switch、select case の様な条件分岐が無いです。

まぁ、賛否は両論ですね。
switch(true) イディオム考察 - Qiita
自分は switch(true) イディオムを使ってなぜクソコードを書くのか - Qiita



Drawのビューがロックされているか? を判断したい時に上手く
判断出来なかったです。

'vba DrawingDocumentをアクティブにして下さい
Option Explicit

Sub CATMain()
    
    Dim sel As Variant
    Set sel = CATIA.ActiveDocument.selection
    
    Dim msg As String
    msg = "ビューを選択してください"
    
    sel.Clear
    Select Case sel.SelectElement2(Array("DrawingView"), msg, False)
        Case "Cancel", "Undo", "Redo"
            Exit Sub
    End Select
    
    Dim vi As DrawingView
    Set vi = sel.Item(1).Value
    
    Dim res As Boolean
    
    '正統派
    msg = "IF : "
    If vi.LockStatus Then
        Debug.Print msg & "Lock"
    Else
        Debug.Print msg & "UnLock"
    End If
    
    'こだわり派
    msg = "IIF : "
    msg = msg & IIf(vi.LockStatus, "Lock", "UnLock")
    Debug.Print msg
    
    '邪道派
    msg = "SELECT CASE : "
    Select Case True
        Case vi.LockStatus
            Debug.Print msg & "Lock"
        Case Else
            Debug.Print msg & "UnLock"
    End Select
End Sub

Drawをアクティブにし、ロックされていないビューを選択すると

IF : UnLock
IIF : UnLock
SELECT CASE : UnLock

でOKなんですが、ロックされているビューを選択すると

IF : Lock
IIF : Lock
SELECT CASE : UnLock

"Select Case True" だけが上手く判断出来ていないんです。
理由はわからないのですが、上手く行かないので避けておかなきゃ・・・。

ビューの場合、ロックされていなくて、参照ビューをもっていなくて、
分離されていなくて・・・ の様に異なるプロパティを単純にクリアした
ものだけ処理したい場合は、

ELSE IF → ネストが深くなってイヤ(Excelの複雑な式みたいになると混乱する)
IFのOR → 1行長い
IIF → 条件内が長くなりIFと変わらない
フラグ立てる → 一度しか使わない変数を作りたくない

とイロイロ方法が有りそうなのですが、
クリアしなかった条件によって ”〇〇の条件が不足しています”
と警告したい場合に一番清楚に書けるのが "Select Case True" かな?
と思い、ここ数年は好んで使用していますがどうでしょう?
(今回は上手くいかなかったのですが)

2D属性リンクを扱いたい8

こちらの続きです。
2D属性リンクを扱いたい7 - C#ATIA

こちらの「GetLinksInfo.bas」でリンク情報が手に入ったので、
セルのオブジェクト名を書き込むのをやめて、リンク情報を書き込む
ことにします。
ファイル間リンクの取得9 - C#ATIA

'vba CheckAttributeLink Ver0.0.1
'using-'KCL0.0.13' 'GetLinksInfo ver0.0.2'  by Kantoku
'指定したDrawTableの隣に属性リンク情報テーブルを作成する

Option Explicit

'元テーブルとのマージン距離
Private Const MARGIN_X = 10#

Sub CATMain()
    Dim msg As String
    
    #If VBA7 And Win64 Then
        'ok
    #Else
        msg = "VBA環境が VBA7 & Win64 では無い為" & vbCrLf & _
            "正しく処理正しく処理出来ません!" & vbCrLf & _
            "中止します"
        MsgBox msg, vbExclamation
        Exit Sub
    #End If
    
    'ドキュメントのチェック
    If Not CanExecute("DrawingDocument") Then Exit Sub
    
    Dim dDoc As DrawingDocument
    Set dDoc = CATIA.ActiveDocument
    
    'テーブル選択
    msg = "テーブル選択/ESCキー中止"
    
    Dim tblOri As DrawingTable
    Set tblOri = KCL.SelectItem(msg, "DrawingTable")
    If tblOri Is Nothing Then Exit Sub
    
    KCL.SW_Start
    
    '属性リンク情報取得
    Dim links As Variant
    links = GetLinkInfo(tblOri)
    If UBound(links) < 1 Then
        MsgBox "リンク情報が無い、又は取得に失敗しました"
        Exit Sub
    End If
    
    'ビュー取得
    Dim vi As DrawingView
    Set vi = tblOri.Parent.Parent
    
    'テーブルコピペ
    Dim tblNew As DrawingTable
    Set tblNew = CopyTable(tblOri, vi)
    If tblNew Is Nothing Then
        MsgBox "テーブルのコピペに失敗しました"
        Exit Sub
    End If
    
    '描写停止
    tblOri.ComputeMode = CatTableComputeOFF
    tblNew.ComputeMode = CatTableComputeOFF
    
    'テーブル幅取得
    Dim moveX As Double
    moveX = GetColumnSizeAll(tblNew)
    tblNew.X = (tblNew.X + moveX + MARGIN_X) / vi.scale2
    
    'テーブルにオブジェクト名記入
    'WriteCellName tblNew
    
    'セル辞書作成
    Dim cellDic As Object
    Set cellDic = InitCellDic(tblOri, tblNew)
    If cellDic.count < 1 Then
        MsgBox "セル情報の取得に失敗しました"
        GoTo fin
    End If
    
    'リンク情報書き込み
    Call PushInfo(cellDic, links)
    
fin:
    '描写
    tblOri.ComputeMode = CatTableComputeON
    tblNew.ComputeMode = CatTableComputeON
    
    MsgBox "done : " & KCL.SW_GetTime & "s"
    
End Sub

Private Sub PushInfo( _
    ByVal dic As Object, _
    ByVal infos As Variant)
    
    Dim i As Long
    Dim dt As DrawingText
    For i = 0 To UBound(infos)
        If Not dic.Exists(infos(i)(0)) Then GoTo continue
        
        Set dt = dic.Item(infos(i)(0))
        dt.Text = dt.Text & vbCrLf & ConvPrmValue(infos(i)(1))
        dt.TextProperties.Bold = 1
continue:
    Next
    
End Sub

'先頭部(パートNo)削除
Private Function ConvPrmValue( _
    ByVal txt As String) _
    As String
    
    Dim idx As Long
    idx = InStr(txt, "\")
    
    If idx > 0 Then
        txt = Mid(txt, idx + 1)
    End If
    
    ConvPrmValue = txt
    
End Function


'セルの辞書作成 - ついでに初期化
'return:dic(key(string)-objName,value(drawtxt)-obj
Private Function InitCellDic( _
    ByVal tbOri As DrawingTable, _
    ByVal tbNew As DrawingTable) As Object
    
    Dim dic As Object
    Set dic = KCL.InitDic()
    
    Dim r As Long, c As Long
    Dim dt As DrawingText
    
    With tbNew
        For r = 1 To .NumberOfRows
            For c = 1 To .NumberOfColumns
                'Existsしなくても大丈夫なはず
                Set dt = .GetCellObject(r, c)
                dt.TextProperties.Bold = 0
                dic.Add tbOri.GetCellObject(r, c).Name, dt
            Next
        Next
    End With
    
    Set InitCellDic = dic
    
End Function


Private Function GetLinkInfo( _
    ByVal tb As DrawingTable) As Variant
    
    Dim sel As selection
    Set sel = CATIA.ActiveDocument.selection
    
    CATIA.HSOSynchronized = False
    
    sel.Clear
    sel.Add tb
    
    Dim ary As Variant
    ary = GetLinksInfo.GetInfo()
    
    sel.Clear
    
    CATIA.HSOSynchronized = True
    
    GetLinkInfo = ary
    
End Function



Private Function CopyTable( _
    ByVal tb As DrawingTable, _
    ByVal vi As DrawingView) _
    As DrawingTable
    
    Dim sel As selection
    Set sel = CATIA.ActiveDocument.selection
        
    CATIA.HSOSynchronized = False
    
    With sel
        .Clear
        .Add tb
        .Copy
        .Clear
        .Add vi
        .Paste
        Set CopyTable = .Item2(1).Value
        .Clear
    End With
    
    CATIA.HSOSynchronized = True
    
End Function

Private Function GetColumnSizeAll( _
    ByVal tb As DrawingTable) As Double
    
    Dim sumClm As Double
    sumClm = 0#
    
    Dim i As Long
    For i = 1 To tb.NumberOfColumns
        sumClm = sumClm + tb.GetColumnSize(i)
    Next
    
    GetColumnSizeAll = sumClm
    
End Function

f:id:kandennti:20190228131349p:plain
前回同様、右側に新たなテーブルを作ります。
セル内の属性リンクを持っているものは、フォントのBoldがON状態に
なり、元の値の下に属性リンクのパスが書き込まれます。
パスをそのまま書き込みだと長ったらしい為、
PartNo以降のパスとしています。

劇的に確認作業が楽になりましたよ!
客先環境下では諦めた・・・。

ファイル間リンクの取得9

こちらの続きです。
ファイル間リンクの取得8 - C#ATIA

ここがゴールでは無いのですが、ファイル間リンク情報をVBAで取得出来るようになりました。
こちらは、リンク情報を取得するだけのものです。
WinAPIを利用している為、標準モジュールで作成してください。

'vba GetLinksInfo.bas ver0.0.2  by Kantoku
'これ自体はKCLには依存していません
'リンクダイアログのテーブルを配列として取得

'ver0.0.1:完成 日本語と英語のみ対応
'ver0.0.2:言語判定精度改善,64bitチェック追加

Option Explicit

'--- win api ---
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

'--
Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" ( _
    ByVal hwnd As LongPtr, _
    ByVal lpClassName As String, _
    ByVal nMaxCount As Long) _
    As Long

'--
Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageW" ( _
    ByVal hwnd As LongPtr, _
    ByVal msg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Any _
    ) As Long

Private Declare PtrSafe Function SendMessageStr Lib "user32" Alias "SendMessageW" ( _
    ByVal hwnd As LongPtr, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As String) _
    As Long

Private Declare PtrSafe Function SendMessageAny Lib "user32" Alias "SendMessageW" ( _
    ByVal hwnd As LongPtr, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    lParam As Any) _
    As Long

Private Const WM_GETTEXT = &HD
Private Const HDM_GETITEMCOUNT = (&H1200 + 0)
Private Const WM_CLOSE = &H10

Private Const LVM_FIRST As Long = &H1000
Private Const LVM_GETITEMCOUNT = (LVM_FIRST + 4)
Private Const LVM_GETITEM As Long = (LVM_FIRST + 5)
Private Const LVM_GETHEADER = (LVM_FIRST + 31)
Private Const LVM_SETITEMSTATE = (LVM_FIRST + 43)
Private Const LVM_GETITEMSTATE = (LVM_FIRST + 44)
Private Const LVM_GETITEMTEXT = LVM_FIRST + 45

'--
Private Declare PtrSafe Function EnumChildWindows Lib "user32" ( _
    ByVal hWndParent As LongPtr, _
    ByVal lpEnumFunc As LongPtr, _
    ByVal lParam As Long) _
    As Long
    
Private Declare PtrSafe Function ShowWindow Lib "user32" ( _
    ByVal hwnd As LongPtr, _
    ByVal nCmdShow As Long) _
    As Long
Private Const SW_HIDE = 0
Private Const SW_SHOW = 5
    
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" ( _
    ByVal lpClassName As String, _
    ByVal lpWindowName As String) _
    As LongPtr

Private Declare PtrSafe Function GetWindow Lib "user32" ( _
    ByVal hwnd As LongPtr, _
    ByVal wCmd As Long) _
    As LongPtr
Private Const GW_HWNDNEXT = 2

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

Private Declare PtrSafe Function GetForegroundWindow Lib "user32" () _
    As LongPtr
    
'--
Private Declare PtrSafe Function GetWindowThreadProcessId Lib "user32" ( _
    ByVal hwnd As LongPtr, _
    lpdwProcessId As Long) _
    As Long

'--
Private Declare PtrSafe Function OpenProcess Lib "kernel32" ( _
    ByVal dwDesiredAccess As Long, _
    ByVal bInheritHandle As Long, _
    ByVal dwProcessId As Long) _
    As LongPtr
    
Private Const PROCESS_VM_OPERATION = &H8
Private Const PROCESS_VM_READ = &H10
Private Const PROCESS_VM_WRITE = &H20

'--
Private Declare PtrSafe Function VirtualAllocEx Lib "kernel32" ( _
    ByVal hProcess As LongPtr, _
    ByVal lpAddress As Long, _
    ByVal dwSize As Long, _
    ByVal flAllocationType As Long, _
    ByVal flProtect As Long) _
    As LongPtr
    
Private Declare PtrSafe Function VirtualFreeEx Lib "kernel32" ( _
    ByVal hProcess As LongPtr, _
    lpAddress As Any, _
    ByVal dwSize As Long, _
    ByVal dwFreeType As Long) _
    As LongPtr
    
Private Const PAGE_READWRITE = &H4&

Private Const MEM_RESERVE = &H2000
Private Const MEM_COMMIT = &H1000
Private Const MEM_RELEASE = &H8000

'--
Private Declare PtrSafe Function CloseHandle Lib "kernel32" ( _
    ByVal hObject As LongPtr) _
    As Long

Private Declare PtrSafe Function ReadProcessMemory Lib "kernel32" ( _
    ByVal hProcess As LongPtr, _
    lpBaseAddress As Any, _
    lpBuffer As Any, _
    ByVal nSize As LongPtr, _
    lpNumberOfBytesWritten As LongPtr) _
    As Long

Private Declare PtrSafe Function WriteProcessMemory Lib "kernel32" ( _
    ByVal hProcess As LongPtr, _
    lpBaseAddress As Any, _
    lpBuffer As Any, _
    ByVal nSize As LongPtr, _
    lpNumberOfBytesWritten As LongPtr) _
    As Long

'-- リストビュー用 構造体
Private Type LVITEM
    mask As Long
    iItem As Long
    iSubitem As Long
    state As Long
    stateMask As Long
    pszText As LongPtr
    cchTextMax As Long
    iImage As Long
    lParam As LongPtr
    iIndent As Long
End Type
Private Const LVIF_TEXT = &H1

'--
Private mLst_hwnd As LongPtr 'リンクダイアログ内リストビューハンドル
Private mLstCount As Long 'リンクダイアログ内リストビュー検索用

'言語別コマンド,ダイアログ文字列
'return:ary (0)-コマンド (1)-未選択時のダイアログ名称 (2)-選択時のダイアログ名称
Private Function GetCommandKey() _
    As Variant
    
    Dim ary As Variant
    Select Case GetLanguage
        Case "en"
            ary = Array("Links...", "Links of document", "Links of element")
        Case "ja"
            ary = Array("リンク...", "ドキュメントのリンク", "エレメントのリンク")
        Case Else
            ary = Array()
    End Select
    
    GetCommandKey = ary
End Function


'リンクダイアログのテーブルを配列として取得
Function GetInfo() _
    As Variant
    
    '64bit check
    #If VBA7 And Win64 Then
        'ok
    #Else
        msg = "VBA環境が VBA7 & Win64 では無い為" & vbCrLf & _
            "正しく処理正しく処理出来ません!" & vbCrLf & _
            "中止します"
        MsgBox msg, vbExclamation
        Exit Function
    #End If
    
    '初期化
    GetInfo = Array()
    mLstCount = 0
    Dim msg As String
    
    Dim cmdkey As Variant
    cmdkey = GetCommandKey()
    If UBound(cmdkey) < 1 Then
        msg = "CATIAの言語判定が出来ない" & vbCrLf & _
            "又は、未対応の言語設定です"
        MsgBox msg, vbExclamation
        Exit Function
    End If
    
    Dim dlgkey As String
    If CATIA.ActiveDocument.Selection.Count2 < 1 Then
        dlgkey = cmdkey(1)
    Else
        dlgkey = cmdkey(2)
    End If
    
    'コマンド実行
    CATIA.StartCommand CStr(cmdkey(0))
    CATIA.RefreshDisplay = True
    
    'リンクダイアログ取得
    Dim hwnd As LongPtr 'リンクダイアログハンドル
    hwnd = FindWindowLike(dlgkey)
    ShowWindow hwnd, SW_HIDE
    If hwnd < 1 Then Exit Function
    
    'リンクダイアログ内のリストビュー(SysListView32)ハンドル取得
    Sleep 100
    Call EnumChildWindows(hwnd, AddressOf CallBack_FindChildWindow, 0)
    If mLst_hwnd < 1 Then Exit Function
    
    'Row数
    Dim rows As Long
    rows = SendMessageStr(mLst_hwnd, LVM_GETITEMCOUNT, 0, 0)
    
    'リストビューヘッダーのハンドル取得 : Column数取得に必要
    Dim h_hwnd As Long
    h_hwnd = SendMessageStr(mLst_hwnd, LVM_GETHEADER, 0, 0)

    'Column数
    Dim cols As Long
    cols = SendMessageStr(h_hwnd, HDM_GETITEMCOUNT, 0, 0)
    If rows < 1 Then Exit Function
    
    
    'セル値取得
    Dim infos() As Variant
    ReDim infos(rows - 1)
    
    Dim info() As String
    Dim r As Long, c As Long
    For r = 0 To rows - 1
        ReDim info(cols - 1)
        For c = 0 To cols - 1
            info(c) = GetCellValue(mLst_hwnd, r, c)
        Next
        infos(r) = info
    Next
        
    'リンクダイアログ閉じる
    ShowWindow hwnd, SW_SHOW
    Call SendMessage(hwnd, WM_CLOSE, 0, ByVal 0&)
    
    GetInfo = infos
    'MsgBox UBound(infos)
    
End Function

'セル値取得
Private Function GetCellValue( _
    ByVal hwnd As LongPtr, _
    ByVal row As Long, _
    ByVal clm As Long) _
    As String
    
    'プロセスID
    Dim prcId As Long
    Call GetWindowThreadProcessId(hwnd, prcId)
    If prcId = 0 Then
        Debug.Print "プロセスID NG"
        Exit Function
    End If
    
    'プロセスハンドル
    Dim prcHwnd As LongPtr
    prcHwnd = OpenProcess(PROCESS_VM_OPERATION Or _
                          PROCESS_VM_READ Or _
                          PROCESS_VM_WRITE, _
                          False, _
                          prcId)
    If prcHwnd = 0 Then
        Debug.Print "プロセスハンドル NG"
        Exit Function
    End If
    
    '書き出し準備
    Dim txtVi As String
    txtVi = String(255, vbNullChar)
    'txtVi = Space$(255)
    Dim txtViPtr As LongPtr
    txtViPtr = StrPtr(txtVi)
    
    Dim txtViSiz As LongPtr
    txtViSiz = LenB(txtVi)
    
    Dim txtViAlc As LongPtr
    txtViAlc = VirtualAllocEx(prcHwnd, _
                              0&, _
                              txtViSiz, _
                              MEM_RESERVE Or MEM_COMMIT, _
                              PAGE_READWRITE)
    
    Dim typLstItm As LVITEM
    
    Dim typViPtr As LongPtr
    typViPtr = VarPtr(typLstItm)
    
    Dim typViSiz As LongPtr
    typViSiz = LenB(typLstItm)
    
    Dim typViAlc As LongPtr
    typViAlc = VirtualAllocEx(prcHwnd, _
                              0&, _
                              typViSiz, _
                              MEM_RESERVE Or MEM_COMMIT, _
                              PAGE_READWRITE)
    
    With typLstItm
        .cchTextMax = 255
        .iItem = row
        .iSubitem = clm
        .mask = LVIF_TEXT
        .pszText = txtViAlc
    End With
    
    '書き出し
    Call WriteProcessMemory(prcHwnd, _
                            ByVal txtViAlc, _
                            ByVal txtViPtr, _
                            txtViSiz, _
                            0)
                            
    Call WriteProcessMemory(prcHwnd, _
                            ByVal typViAlc, _
                            ByVal typViPtr, _
                            typViSiz, _
                            0)
                            
    Call SendMessageAny(hwnd, _
                        LVM_GETITEM, _
                        ByVal 0, _
                        ByVal typViAlc)
    'ここ
    Call ReadProcessMemory(prcHwnd, _
                           ByVal txtViAlc, _
                           ByVal txtViPtr, _
                           txtViSiz, _
                           0)
    
    '値取得
    'vbFromUnicode
    'txtVi = StrConv(txtVi, vbUnicode, 1041)
    txtVi = StrConv(txtVi, vbUnicode)
    'txtVi = StrConv(txtVi, vbWide)
    GetCellValue = Left(txtVi, InStr(1, txtVi, vbNullChar) - 1)
    
    'プロセス終了
    Call VirtualFreeEx(prcHwnd, _
                       ByVal txtViAlc, _
                       txtViSiz, _
                       MEM_RELEASE)
                       
    Call VirtualFreeEx(prcHwnd, _
                       ByVal typViAlc, _
                       typViSiz, _
                       MEM_RELEASE)
                       
    Call CloseHandle(prcHwnd)
            
End Function

'ダイアログ内リストビュ-
Private Function CallBack_FindChildWindow( _
    ByVal hwnd As LongPtr, _
    ByVal prm As Long) _
    As Long

    Dim cls As String
    cls = String(255, vbNullChar)
    
    Dim cnt As Long
    cnt = GetClassName(hwnd, cls, 63&)
    cls = Left(cls, cnt)
    
    If cls = "SysListView32" Then
        mLstCount = mLstCount + 1
        If mLstCount > 1 Then '2個目のリストビュー
            mLst_hwnd = hwnd
            CallBack_FindChildWindow = 0
            Exit Function
        End If
    End If
    CallBack_FindChildWindow = 1 '終了サイン
    
End Function

'指定文字を含んだWindow取得
Private Function FindWindowLike( _
    key As String) _
    As LongPtr
    
    Dim hwnd As LongPtr
    Dim winTxt As String
    Dim cnt As Integer
    hwnd = GetForegroundWindow
    
    Do Until hwnd = 0
        winTxt = String(255, vbNullChar)
        cnt = GetWindowText(hwnd, winTxt, 255)
        winTxt = Left(winTxt, cnt)
        
        If InStr(1, LCase(winTxt), LCase(key)) > 0 Then Exit Do
        hwnd = GetWindow(hwnd, GW_HWNDNEXT)
    Loop
    FindWindowLike = hwnd
    
End Function

'言語判定
Private Function GetSelectedItems() _
    As Collection
    
    Dim sel As Selection
    Set sel = CATIA.ActiveDocument.Selection
    
    Dim lst As Collection
    Set lst = New Collection
    
    Dim i As Long
    For i = 1 To sel.Count2
        lst.Add sel.Item2(i).Value
    Next
    
    Set GetSelectedItems = lst
    
End Function

Private Sub SetSelectItems( _
    ByVal lst As Collection)
    
    If lst.count < 1 Then Exit Sub
    
    Dim sel As Selection
    Set sel = CATIA.ActiveDocument.Selection
    
    CATIA.HSOSynchronized = False
    
    Dim elm As AnyObject
    For Each elm In lst
        sel.Add elm
    Next
    
    CATIA.HSOSynchronized = True
    
End Sub


'言語判定
Private Function GetLanguage() _
    As String
    
    GetLanguage = "non"
    If CATIA.Windows.count < 1 Then Exit Function
    
    GetLanguage = "other"
    
    Dim lst As Collection
    Set lst = GetSelectedItems()
    
    CATIA.ActiveDocument.Selection.Clear
    SendKeys "{ESC}"
    Sleep 100
    SendKeys "{ESC}"
    CATIA.RefreshDisplay = True
    
    Dim st As String
    st = CATIA.StatusBar
    
    Select Case True
        Case ExistsKey(st, "object")
            GetLanguage = "en"
        Case ExistsKey(st, "objet")
            GetLanguage = "fr"
        Case ExistsKey(st, "Objekt")
            GetLanguage = "de"
        Case ExistsKey(st, "oggetto")
            GetLanguage = "it"
        Case ExistsKey(st, "オブジェクト")
            GetLanguage = "ja"
        Case ExistsKey(st, "объект")
            GetLanguage = "ru"
        Case ExistsKey(st, "象或")
            GetLanguage = "zh"
        Case Else
            Select Case Len(st)
                Case 13
                    GetLanguage = "ko"
                Case 23
                    GetLanguage = "ja"
                Case Else
                
            End Select
    End Select
    
    Call SetSelectItems(lst)
    
End Function

Private Function ExistsKey( _
    ByVal txt As String, _
    ByVal key As String) _
    As Boolean
    
    ExistsKey = IIf(InStr(LCase(txt), LCase(key)) > 0, _
        True, _
        False)
End Function

WinAPIがグリグリゴリゴリで吐き気がしそうなやつです。
”もうちょっとこうしたら効率が良いんじゃないの?”
と言うご意見があれば教えて頂けると助かります。
(動いたからもう見たくない)

GetInfo関数を呼び出すと、アクティブなドキュメントのリンク情報を配列で
受け取れます。
f:id:kandennti:20190227181810p:plain
戻り値の配列の状態は
array(赤側のインデックス)(緑側のインデックス)
で全てString型です。(緑側は0~9の10個固定になるはず)

StartCommandを利用している為、CATIAの言語に依存されますが、
一応、日本語、英語は対応させています。日本語のみ確認しています。
日本語、英語は対応させています。但し、VBA7、WIN64が条件です。
こちらを参照してください。(当方OS:Win7 64bit Catia V5-6 R2015)
ファイル間リンクの取得10 - C#ATIA
(他言語は要望があれば追加しますが、面倒です)

又、C#時にはドキュメント全体のリンク情報しか取得できませんでしたが、
VBA版はオブジェクトを選択した状態でGetInfo関数を呼び出すと、
そのオブジェクトのリンク情報のみを取得出来るようにしています。
(感覚的に手動時と同じ挙動の方が自然ですよね?)


こちらは上記の利用したサンプルです。

'vba sample_GetLinksInfo
'using-'KCL0.0.13','GetLinksInfo'  by Kantoku

'GetLinksInfoを使ったサンプルです
'手動同様に何も選択していなければアクティブなDocumentの全リンク情報
'選択していれば、選択しているものだけのリンク情報を
'ファイルと同一のフォルダにCSVファイルで出力します


Sub CATMain()

    Dim msg As String
    
    'ドキュメントのチェック
    Dim filter As String
    filter = "DrawingDocument,PartDocument,ProductDocument"
    If Not CanExecute(filter) Then Exit Sub
    
    'Doc
    Dim doc As Document
    Set doc = CATIA.ActiveDocument
    
    '出力パス
    Dim path As String
    path = doc.FullName
    If InStr(1, path, "\") < 1 Then
        msg = "出力パスが確定しない為、一度保存してください!"
        MsgBox msg, vbExclamation
        Exit Sub
    End If
    
    Dim dmy As Variant
    dmy = KCL.SplitPathName(path)
    dmy(1) = dmy(1) & "_LinksInfo"
    dmy(2) = "csv"
    
    Dim exp As String
    exp = KCL.GetNewName(KCL.JoinPathName(dmy))
    
    '確認
    msg = "リンク情報を出力しますか?"
    If MsgBox(msg, vbQuestion + vbYesNo) = vbNo Then Exit Sub
    
    Dim infos As Variant
    infos = GetLinksInfo.GetInfo()
    
    If UBound(infos) < 1 Then
        msg = "外部リンクが無い、又は正常に取得できませんでした!"
        MsgBox msg, vbExclamation
        Exit Sub
    End If
    
    '書き出し
    Call KCL.WriteFile(exp, Info2Str(infos))
    
    '終わり
    MsgBox "done"
    
End Sub

Private Function Info2Str( _
    ary As Variant)
    
    Dim ex() As Variant
    ReDim ex(UBound(ary))
    
    Dim i As Long
    For i = 0 To UBound(ary)
        ex(i) = Join(ary(i), ",")
    Next
    
    Info2Str = Join(ex, vbCrLf)
    
End Function

DrawingDocument,PartDocument,ProductDocument問わず、
アクティブなドキュメントと同じフォルダ内に、リンク情報の
CSVファイルを作成します。
選択時、未選択時で出力される内容が変わることが確認出来ると
思います。

もうちょっとで届きそう!

※Ver0.0.2にしました。言語判定精度改善,64bitチェック追加

ファイル間リンクの取得8

こちらの続きです。
ファイル間リンクの取得2 - C#ATIA
3年程前に断念したVBAでのファイル間リンク情報取得なのですが、
昨日から少し手ごたえを感じています。

元にしているコードはこちらです。
Catia V5 Get Links
過去に紹介したサイトが幾つも消えてしまっているのですが、
消えていなくて助かっています。が、あまりにコードが汚いのも本音です。

「リンク...」(英語環境 Links...)コマンドを実行し、出てくるダイアログの情報を
WinAPIでゴリゴリに取得しようと言うマクロなのですが、大元は32bitの頃に
作成されたもので、前回取り組んだ際はOSが64bitでVBAが32bitだったような
記憶です。

まだ途中ですが、ダイアログのリストビューにアクセスする辺りまでのコードです。

'vba リンクダイアログ取得テスト

Option Explicit

'--- win api ---
Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" ( _
    ByVal hwnd As LongPtr, _
    ByVal lpClassName As String, _
    ByVal nMaxCount As Long) _
    As Long

'--
Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" ( _
    ByVal hwnd As LongPtr, _
    ByVal msg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Any _
    ) As Long 'Ptr

Private Declare PtrSafe Function SendMessageStr Lib "user32" Alias "SendMessageA" ( _
    ByVal hwnd As LongPtr, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As String) _
    As Long 'Ptr

Private Declare PtrSafe Function SendMessageAny Lib "user32" Alias "SendMessageA" ( _
    ByVal hwnd As LongPtr, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    lParam As Any) _
    As Long 'Ptr

Private Const WM_GETTEXT = &HD
Private Const HDM_GETITEMCOUNT = (&H1200 + 0)
Private Const WM_CLOSE = &H10

Private Const LVM_FIRST As Long = &H1000
Private Const LVM_GETITEMCOUNT = (LVM_FIRST + 4)
Private Const LVM_GETITEM As Long = (LVM_FIRST + 5)
Private Const LVM_GETHEADER = (LVM_FIRST + 31)
Private Const LVM_SETITEMSTATE = (LVM_FIRST + 43)
Private Const LVM_GETITEMSTATE = (LVM_FIRST + 44)
Private Const LVM_GETITEMTEXT = LVM_FIRST + 45

'--
Private Declare PtrSafe Function EnumChildWindows Lib "user32" ( _
    ByVal hWndParent As LongPtr, _
    ByVal lpEnumFunc As LongPtr, _
    ByVal lParam As Long) _
    As Long
    
Private Declare PtrSafe Function ShowWindow Lib "user32" ( _
    ByVal hwnd As LongPtr, _
    ByVal nCmdShow As Long) _
    As Long
Private Const SW_HIDE = 0
Private Const SW_SHOW = 5
    
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" ( _
    ByVal lpClassName As String, _
    ByVal lpWindowName As String) _
    As LongPtr

Private Declare PtrSafe Function GetWindow Lib "user32" ( _
    ByVal hwnd As LongPtr, _
    ByVal wCmd As Long) _
    As LongPtr
Private Const GW_HWNDNEXT = 2

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

Private Declare PtrSafe Function GetForegroundWindow Lib "user32" () _
    As LongPtr

Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

'--
Private F_hwnd As LongPtr
Private L_hwnd As LongPtr
Private ListCount As Long

Sub CATMain()

    'コマンド実行
    CATIA.StartCommand ("リンク...") ' ("Links...") '
    CATIA.RefreshDisplay = True
    
    'リンクダイアログ取得
    F_hwnd = FindWindowLike("ドキュメントのリンク") '("Links of document") '
    'ShowWindow F_hwnd, SW_HIDE
    
    'リンクダイアログ内のリストビュー(SysListView32)ハンドル取得
    Sleep 100
    Call EnumChildWindows(F_hwnd, AddressOf EnumChildWindow, 0)
    
    'Row数
    Dim rows As Long
    rows = SendMessageStr(L_hwnd, LVM_GETITEMCOUNT, 0, 0)
    
    'リストビューヘッダーのハンドル取得 : Column数取得に必要
    Dim hWndHeader As Long 'Long
    hWndHeader = SendMessage(L_hwnd, LVM_GETHEADER, 0, ByVal 0&)
    
    'Column数
    Dim cols As Long
    cols = SendMessageStr(hWndHeader, HDM_GETITEMCOUNT, 0, 0)
        
    'リンクダイアログ閉じる
    'ShowWindow F_hwnd, SW_SHOW
    SendMessageAny F_hwnd, WM_CLOSE, 0, 0
    
    Stop
End Sub

Private Function EnumChildWindow( _
    ByVal hChild As LongPtr, _
    ByVal lParam As LongPtr) _
    As Long
    
    Dim iClass As String
    Dim iText As String
    Dim j As LongPtr
    
    iClass = String(255, vbNullChar) 'Space(256)
    j = GetClassName(hChild, iClass, 63)
    iClass = Left(iClass, CLng(j))
    iText = String(255, vbNullChar) 'Space(256)
    j = SendMessageStr(hChild, WM_GETTEXT, 255, iText)
    iText = Left(iText, CLng(j))
    If iClass = "SysListView32" Then
        ListCount = ListCount + 1
        If ListCount = 2 Then
            L_hwnd = hChild: EnumChildWindow = 0: Exit Function
        End If
    End If
    EnumChildWindow = 1 ' Continua enumerarea
    
End Function

Private Function FindWindowLike( _
    strPartOfCaption As String) _
    As LongPtr
    
    Dim hwnd As LongPtr
    Dim strCurrentWindowText As String
    Dim r As Integer
    hwnd = GetForegroundWindow
    Do Until hwnd = 0
        strCurrentWindowText = String(255, vbNullChar) 'Space(256)
        r = GetWindowText(hwnd, strCurrentWindowText, 255)
        strCurrentWindowText = Left$(strCurrentWindowText, r)
        If InStr(1, LCase(strCurrentWindowText), LCase(strPartOfCaption)) <> 0 Then GoTo Found
        hwnd = GetWindow(hwnd, GW_HWNDNEXT)
    Loop
    Exit Function
Found:
    FindWindowLike = hwnd
    
End Function

正直な所、
・WinAPIの引き数・戻り値の型に自信が有りません
・EnumChildWindow、FindWindowLikeは動くレベルまでの
 修正しかしていません。

実際に実行してみるとこんな感じです。
f:id:kandennti:20190227111409p:plain
ローカルウィンドウに表示されているものは、リンクのダイアログに入っている
リストビューの行と列の数等で、それなりに取得できているのがわかります。
(あまりに汚いのでコードを記載していませんが、その後のコードで
 リンク情報は全て取得出来ています)

悩んでいるのは、2度目以降実行すると
f:id:kandennti:20190227111419p:plain
数値が取得出来なくなります。何故?

単に取得する際のSendMessage類が機能しないのか?
一回目の実行後の終了の仕方が悪いのか?
何をどうすれば良いのか・・・。

但し、この様な操作をすると、再度取得が出来ます。
例えば、WinAPIのSendMessage関数の戻り値の型をこんな感じに
修正します。

Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" ( _
・・・
    ) As Long 'Ptr

 ↓

    ) As LongPtr

当然、SendMessage関数の利用先では型の不一致でエラーとなります。
そこで、SendMessage関数の戻り値の型を元に戻すと再び正しく取得出来ます。
但し1度だけです。

感覚的に、宣言セクションにある程度影響のある修正を加えると、1度だけ
正しく取得出来ているような感じです。
f:id:kandennti:20190227111435p:plain
どうでも良い部分にスペースを入れて、削除ぐらいではダメなんですが。

この様な現象を経験された方いらっしゃいませんか?
どの様に対策を取れば良いのだろう?
不安定な挙動なので、何かしらが正しくなくてギリギリ動いているのは
実感しているのですが、ゴールへの道筋があるのに辿り着けない・・・。

2D属性リンクを扱いたい7

こちらの
2D属性リンクを扱いたい6 - C#ATIA

ですが、内容的にはこちらを変更したものです。
2D属性リンクを扱いたい4 - C#ATIA

前回CSVファイルとしてエクスポートしたのですが、
同じレイアウトでセルのオブジェクト名を記載したテーブルを
横に作成した方が確認が楽な事に気が付きました。

'vba sample_CreateCellNameTable using-'KCL0.0.13'  by Kantoku
'指定したDrawTableを隣にコピペしセルのオブジェクト名を書き出す

Option Explicit

'元テーブルとのマージン距離
Private Const MARGIN_X = 10#

Sub CATMain()

    'ドキュメントのチェック
    If Not CanExecute("DrawingDocument") Then Exit Sub
    
    Dim dDoc As DrawingDocument
    Set dDoc = CATIA.ActiveDocument
    
    'テーブル選択
    Dim msg As String
    msg = "テーブル選択/ESCキー中止"
    
    Dim dwTblOri As DrawingTable
    Set dwTblOri = KCL.SelectItem(msg, "DrawingTable")
    If dwTblOri Is Nothing Then Exit Sub
    
    'テーブルコピペ
    Dim dwTblNew As DrawingTable
    Set dwTblNew = CopyTable(dwTblOri)
    If dwTblNew Is Nothing Then
        MsgBox "テーブルのコピペに失敗しました"
        Exit Sub
    End If
    
    'テーブル幅取得
    Dim moveX As Double
    moveX = GetColumnSizeAll(dwTblNew)
    dwTblNew.X = dwTblNew.X + moveX + MARGIN_X
    
    'テーブルにオブジェクト名記入
    WriteCellName dwTblNew
    
    MsgBox "done"
    
End Sub

Private Sub WriteCellName( _
    ByVal table As DrawingTable)
    
    Dim r As Long, c As Long
    
    With table
        For r = 1 To .NumberOfRows
            For c = 1 To .NumberOfColumns
                .SetCellString r, c, .GetCellObject(r, c).name
            Next
        Next
    End With
    
End Sub

Private Function CopyTable( _
    ByVal table As DrawingTable) _
    As DrawingTable
    
    Dim sel As selection
    Set sel = CATIA.ActiveDocument.selection
    
    Dim vi As DrawingView
    Set vi = KCL.GetParent_Of_T(table, "DrawingView")
    If vi Is Nothing Then Exit Function
    
    CATIA.HSOSynchronized = False
    
    With sel
        .Clear
        .Add table
        .Copy
        .Clear
        .Add vi
        .Paste
        Set CopyTable = .Item2(1).Value
        .Clear
    End With
    
    CATIA.HSOSynchronized = True
    
End Function

Private Function GetColumnSizeAll( _
    ByVal table As DrawingTable) As Double
    
    Dim sumClm As Long
    sumClm = 0
    
    Dim i As Long
    For i = 1 To table.NumberOfColumns
        sumClm = sumClm + table.GetColumnSize(i)
    Next
    
    GetColumnSizeAll = sumClm
    
End Function

レイアウトは元のテーブルと同じで、隣にセル名の入ったテーブルを
作ります。
f:id:kandennti:20190226153157p:plain
後は、やっぱりチマチマと確認です・・・。

新たに作成したテーブルは元のテーブルをコピペして
セルの中身を書き換えただけの為、こちらの問題から
属性リンクが残っています。
2D属性リンクを扱いたい2 - C#ATIA
未だに属性リンクをマクロで削除する方法が見つかりません。


又、一部KCLの関数がエラーになり止まってしまう事がシバシバ
起きているので、こっそりVer0.0.12 → Ver0.0.13 に更新しました。
(例外入れただけです)
非常に個人的なCATVBA用ライブラリ - C#ATIA

2D属性リンクを扱いたい6

こちらの続きです。
2D属性リンクを扱いたい5 属性リンク付き座標テーブル - C#ATIA

処理が満足出来るレベルまで速くなりました。

'vba AttributeLinkTable Ver0.0.2 using-'KCL0.0.12'  by Kantoku
'属性リンク付き座標テーブル-平面上の点のみ対応

'ver0.0.1:完成
'ver0.0.2:タイトルを形状セット名に変更,高速化

Private Const KEY_H = "H"               'パラメータ用Hキー
Private Const KEY_V = "V"               'パラメータ用Vキー
Private Const ROWSIZE = 10              'テーブル初期行高さ
Private Const COLUMNSIZE = 35           'テーブル初期列幅

Option Explicit

Sub CATMain()

    'ドキュメントのチェック
    If Not CanExecute("DrawingDocument") Then Exit Sub
    
    Dim dDoc As DrawingDocument
    Set dDoc = CATIA.ActiveDocument
    
    'ビュー選択
    Dim msg As String
    msg = "テーブルを作成する、ビューを選択してください /ESC-終了"
    
    Dim vi As DrawingView
    Set vi = KCL.SelectItem(msg, "DrawingView")
    If vi Is Nothing Then Exit Sub
    
    '形状セット選択
    msg = "平面上の点を含んだ、形状セットを選択してください /ESC-終了"
    
    Dim hBdy As HybridBody
    Set hBdy = SelectItem4(msg, msg, Array("HybridBody"))
    If hBdy Is Nothing Then Exit Sub
    
    'time
    KCL.SW_Start
    
    'リンクPart取得
    Dim lnkPt As Part
    Set lnkPt = KCL.GetParent_Of_T(hBdy, "Part")
    If lnkPt Is Nothing Then
        MsgBox "形状セットのPartが取得できませんでした"
        Exit Sub
    End If
    
    'パラメータ名取得
    Dim prms As Variant
    prms = GetParameters(hBdy)
    If IsEmpty(prms) Then
        msg = "処理すべき点が含まれていませんでした" & vbCrLf & _
            "(平面上の点のみ対応してます)"
        MsgBox msg
        Exit Sub
    End If
    
    'テーブル作成&書き込み
    Call InitTable(prms, vi, hBdy.name)
    
    MsgBox "done : " & KCL.SW_GetTime
    
End Sub

'テーブル作成し投げ込む
Private Sub InitTable( _
    ByVal prms As Variant, _
    ByVal vi As DrawingView, _
    ByVal title As String)
    
    'row
    Dim rowcnt As Long
    rowcnt = UBound(prms)
    
    'Column
    Dim clmcnt As Long
    clmcnt = UBound(prms(0))
    
    'テーブル
    Dim tbl As DrawingTable
    Set tbl = vi.Tables.Add(0, 0, rowcnt + 2, clmcnt + 1, ROWSIZE, COLUMNSIZE) 

    'タイトル
    Dim titles As Variant
    titles = Array(title, KEY_H, KEY_V)
    
    Dim dt As DrawingText
    Dim c As Long
    For c = 0 To clmcnt
        Set dt = tbl.GetCellObject(1, c + 1)
        dt.Text = titles(c)
    Next
    
    '書き出し
    Dim r As Long
    tbl.ComputeMode = CatTableComputeOFF
    For r = 0 To rowcnt
        Set dt = tbl.GetCellObject(r + 2, 1)
        dt.Text = prms(r)(0)
        
        For c = 1 To clmcnt
            Set dt = tbl.GetCellObject(r + 2, c + 1)
            Call dt.InsertVariable(0, 0, prms(r)(c))
        Next
    Next
    tbl.ComputeMode = CatTableComputeON
    
End Sub

'形状セット内の点からパラメータを取得
Private Function GetParameters( _
    ByVal hBdy As HybridBody) As Variant
    
    Dim shps As HybridShapes
    Set shps = hBdy.HybridShapes
    
    'HybridShapePointOnPlaneのみ
    Dim lst As Collection
    Set lst = New Collection
    
    Dim shp As HybridShape
    Dim i As Long
    For i = 1 To shps.Count
        If Not typename(shps.Item(i)) = "HybridShapePointOnPlane" Then
            GoTo continue
        End If
        
        lst.Add shps.Item(i)
continue:
    Next
    
    If lst.Count < 1 Then Exit Function '点なし
    
    
    'HVパラメータを取得
    Dim pt As Part
    Set pt = KCL.GetParent_Of_T(hBdy, "Part")
    
    Dim prms As Parameters
    Set prms = pt.Parameters
    
    Dim ary() As Variant
    ReDim ary(lst.Count - 1)
    
    Dim baseName As String
    Dim txtH As String
    Dim txtV As String
    Dim prmH As Parameter
    Dim prmV As Parameter
    Dim subLst As Parameters
    Dim cnt As Long
    
    cnt = -1
    For i = 1 To lst.Count
        Set subLst = prms.SubList(lst.Item(i), False)
        baseName = subLst.GetNameToUseInRelation(lst.Item(i))
        
        txtH = Left(baseName, Len(baseName) - 1) & _
            "\" & KEY_H & Right(baseName, 1)
        txtV = Left(baseName, Len(baseName) - 1) & _
            "\" & KEY_V & Right(baseName, 1)
        
        Set prmH = GetParameter(txtH, subLst)
        Set prmV = GetParameter(txtV, subLst)
        
        If (Not prmH Is Nothing) And (Not prmV Is Nothing) Then
            ary(i - 1) = Array(lst.Item(i).name, prmH, prmV)
            cnt = cnt + 1
        End If
    Next
    
    If cnt < 0 Then Exit Function '点なし
    
    If Not UBound(ary) = cnt Then
        ReDim Preserve ary(cnt)
    End If
    
    GetParameters = ary
    
End Function

'パラメータ取得
Private Function GetParameter( _
    ByVal key As String, _
    ByVal params As Parameters) As Parameter
    
    Set GetParameter = Nothing
    
    Dim prm As Parameter
    Err.Number = 0
    On Error Resume Next
        Set prm = params.Item(key)
    On Error GoTo 0
    
    Set GetParameter = prm
End Function

'SelectElement4
'pram:filter-AryVariant(string)
Private Function SelectItem4( _
    ByVal msg1 As String, _
    ByVal msg2 As String, _
    ByVal filter As Variant) As AnyObject
    
    Dim sel As Variant
    Set sel = CATIA.ActiveDocument.selection
    Dim targetDoc As Variant 'Document 型指定Ng
    
    sel.Clear
    Select Case sel.SelectElement4(filter, msg1, msg2, _
                                   False, targetDoc)
        Case "Cancel", "Undo", "Redo"
            Exit Function
    End Select
    
    Dim tgtSel As selection
    Set tgtSel = targetDoc.selection
    Set SelectItem4 = tgtSel.Item2(1).Value
    
    sel.Clear
    tgtSel.Clear
End Function

f:id:kandennti:20190222190200p:plain
赤印部分は選択した形状セット名にした方が自然な感じがしたので、
そのように変更してみました。
たった19個ですが0.2秒程。 でも昨日は1分近くかかってました。


高速になった要因です。

InitTable関数のこの辺

 ・・・
    '書き出し
    Dim r As Long
    tbl.ComputeMode = CatTableComputeOFF
 ・・・
    tbl.ComputeMode = CatTableComputeON
    ・・・

excelのマクロの様に、セルに書き込んでる際に描写を止めました。
でも、効果は少しです。

効果が大きかったのはGetParameters関数のこの辺りです

 ・・・
    Dim prmH As Parameter
    Dim prmV As Parameter
    Dim subLst As Parameters
    Dim cnt As Long
    
    cnt = -1
    For i = 1 To lst.Count
        Set subLst = prms.SubList(lst.Item(i), False)'←ここの効果が絶大
        baseName = subLst.GetNameToUseInRelation(lst.Item(i))
        
        txtH = Left(baseName, Len(baseName) - 1) & _
            "\" & KEY_H & Right(baseName, 1)
        txtV = Left(baseName, Len(baseName) - 1) & _
            "\" & KEY_V & Right(baseName, 1)
        
        Set prmH = GetParameter(txtH, subLst)
        Set prmV = GetParameter(txtV, subLst)
 ・・・

パラメータを取得している部分です。こちらに詳しく記載されています。
Efficiently navigating parameter collections | CATIA V5 Automation

予め抜き出すオブジェクトがわかっているなら、SubListでパラメータを
抜き出してから探し出した方が速いってことらしいです。確かに。
baseNameを取得してからHやVを抜き出しているけど、直接出来るかも。


但し、こちらの問題が解決しないので、これ自体はボツになりそう。
DrawingTableのSetCellObjectメソッド機能していない - C#ATIA