MW211 EXIT

devlog
ExcelVBA/昔ながらの文字長
2019年11月29日
昔のExcelでは、全角文字=2バイトだった(ShiftJISだったので)
でも今はUnicodeになったのでその常識が通じない。
でも、それを使いたい場合がある。
ということで、自前でリメンバーLenB、LeftBを。
┌──────────────────────────────────────┐
│'===========================================================================│
│'  ShiftJISバイト長(全角文字=2バイト)                                      │
│'===========================================================================│
│Public Function LenSjis(ByVal 入力 As String) As Long                       │
│    LenSjis = LenB(StrConv(入力, vbFromUnicode))                            │
│End Function                                                                │
├──────────────────────────────────────┤
│'===========================================================================│
│'  ShiftJISバイト長で左から切り抜き                                         │
│'===========================================================================│
│Public Function LeftSjis(ByVal 入力 As String, _                            │
│                         ByVal バイト長 As Long) As String                  │
│    Dim 結果 As String                                                      │
│    結果 = StrConv(LeftB(StrConv(入力, vbFromUnicode), バイト長), vbUnicode)│
│    If LenSjis(結果) > バイト長 Then                                        │
│        結果 = Left(入力, Len(結果) - 1)                                    │
│    End If                                                                  │
│    LeftSjis = 結果                                                         │
│End Function                                                                │
└──────────────────────────────────────┘
分類:ExcelVBA
ExcelVBA/【未解決】エラー時の関数名
2019年10月29日
例えば以下のような例外が発生した場合に、どの関数(どのクラスのどのメソッド)で
発生したかをログに出力できたらすばらしい。
┌──────────────────────────────────────┐
│    On Error GoTo l_Catch                                                   │
│    MsgBox 1 / 0                                                            │
│    Exit Sub                                                                │
│l_Catch:                                                                    │
│    MsgBox Err.Description                          '→「0で除算しました。」│
└──────────────────────────────────────┘

でも、その簡単な方法が今のところ見当たらない。
例えば以下みたいに簡単に指定できればいいのだが。
┌──────────────────────────────────────┐
│    MsgBox __CLASS__                                                        │
│    MsgBox __METHOD__                                                       │
│    MsgBox __FUNC__                                                         │
└──────────────────────────────────────┘

まず、実行中の行番号がわかれば以下でいける。
#といっても、自身のソースファイル名を指定(With句の部分)する必要があるが
  モジュールなら「Application.VBE.ActiveCodePane.CodeModule」で取得できるが
┌──────────────────────────────────────┐
│With ThisWorkbook.VBProject.VBComponents("Moduleモジュール").CodeModule     │
│    MsgBox .ProcOfLine(Erl, 0)                                '→関数名     │
│End With                                                                    │
├──────────────────────────────────────┤
│With ThisWorkbook.VBProject.VBComponents("Classクラス").CodeModule          │
│    MsgBox .Name()                                             '→クラス名  │
│    MsgBox .ProcOfLine(Erl, 0)                                 '→メソッド名│
│End With                                                                    │
└──────────────────────────────────────┘
行番号は隠し関数の「Erl()」で取得できるのだが、微妙なのがその前準備。

普段使わない行番号を振っておかなければならないのだ。
┌──────────────────────────────────────┐
│77: On Error GoTo l_Catch                                                   │
│    MsgBox 1 / 0                                                            │
│    Exit Sub                                                                │
│l_Catch:                                                                    │
│    MsgBox Erl                                                     '→「77」│
├──────────────────────────────────────┤
│77: On Error GoTo l_Catch                                                   │
│88: MsgBox 1 / 0                                                            │
│    Exit Sub                                                                │
│l_Catch:                                                                    │
│    MsgBox Erl                                                     '→「88」│
└──────────────────────────────────────┘
かなりめんどくさい、これは却下か。

他にもっと簡単な方法はないものか。
分類:ExcelVBA
ExcelVBA/EXE実行(2)WScript.Exec()
2019年10月05日
WSHを使ってのEXE実行の例。
┌──────────────────────────────────────┐
│Dim 標準出力 As String                                                      │
│Dim objWSH As Object                                                        │
│Set objWSH = CreateObject("WScript.Shell")                                  │
│Dim objEXEC As Object                                                       │
│Set objEXEC = objWSH.Exec("C:\TOOLS\TEST.exe")                              │
│With objEXEC                                                                │
│    Do While .Status = 0                                                    │
│        DoEvents                                                            │
│    Loop                                                                    │
│    標準出力 = .StdOut.ReadAll                                              │
│End With                                                                    │
│MsgBox 標準出力                                                             │
└──────────────────────────────────────┘
これだと標準出力などを取得できる。
分類:ExcelVBA
ExcelVBA/EXE実行(1)Shell()
2019年10月04日
Shell()を使ってのEXE実行の例。
┌──────────────────────────────────────┐
│Dim プロセスID As Long                                                      │
│プロセスID = Shell("C:\TOOLS\TEST.exe", 1)                                  │
│If プロセスID = 0 Then                                                      │
│    MsgBox "起動に失敗しました"                                             │
│    Exit Sub                                                                │
│End If                                                                      │
│MsgBox "実行完了"                                                           │
└──────────────────────────────────────┘
実行できるだけあまり多くを期待しない方がよさそうだ。(よくわからない)
分類:ExcelVBA
ExcelVBA/コメントのマクロ制御
2019年09月13日
こんな感じ。
┌──────────────────────────────────────┐
│With ActiveCell                                                             │
│    If TypeName(.Comment) = "Nothing" Then                    ' 存在チェック│
│        .AddComment "コメント" & vbLf & "します"              ' 追加        │
│    Else                                                                    │
│        MsgBox .Comment.Text                                  ' 取得        │
│        .ClearComments                                        ' 削除        │
│    End If                                                                  │
│End With                                                                    │
└──────────────────────────────────────┘
分類:ExcelVBA
ExcelVBA/ActiveXコントロールのCaption
2019年09月12日
シート内のActiveXコントロールをループする処理は以下の通り。
┌──────────────────────────────────────┐
│Dim 図形 As Object                                                          │
│With ActiveSheet                                                            │
│    For Each 図形 In .Shapes                                                │
│        If 図形.Type = msoOLEControlObject Then                             │
│            Debug.Print 図形.Name                                           │
│        End If                                                              │
│    Next 図形                                                               │
│End With                                                                    │
└──────────────────────────────────────┘

じゃということで、ラベルのキャプションを取得しようとしたらエラーとなる。
┌──────────────────────────────────────┐
│Dim 図形 As Object                                                          │
│With ActiveSheet                                                            │
│    For Each 図形 In .Shapes                                                │
│        If 図形.Type = msoOLEControlObject Then                             │
│            Debug.Print 図形.Caption                                        │
│        End If                                                              │
│    Next 図形                                                               │
│End With                                                                    │
└──────────────────────────────────────┘

以下だとOKのようだ。
┌──────────────────────────────────────┐
│Dim 図形 As Object                                                          │
│With ActiveSheet                                                            │
│    For Each 図形 In .Shapes                                                │
│        If 図形.Type = msoOLEControlObject Then                             │
│            Debug.Print 図形.OLEFormat.Object.Object.Caption                │
│        End If                                                              │
│    Next 図形                                                               │
│End With                                                                    │
└──────────────────────────────────────┘
分類:ExcelVBA
ExcelVBA/ActiveXが存在するか?
2019年09月11日
例えば、特定のラベルの値(キャプション)を取得する場合に
そのラベルが存在しない場合にはエラーとなる。

これを回避するには事前に存在チェックする必要がある。

しかし、その存在チェックは簡単にはできない。

以下のようにActiveXコントロールを検索し
該当する名称のものがあるかいないかで判断する形となる。
┌──────────────────────────────────────┐
│Dim 図形 As Shape                                                           │
│With シート                                                                 │
│    For Each 図形 In .Shapes                                                │
│        If 図形.Type = msoOLEControlObject Then                             │
│            MsgBox 図形.Name                                                │
│        End If                                                              │
│    Next 図形                                                               │
│End With                                                                    │
└──────────────────────────────────────┘
自前のサブ関数を作るのがよいだろう。
分類:ExcelVBA
ExcelVBA/引数を配列にする方法
2019年09月10日
┌──────────────────────────────────────┐
│Call 関数(Array("a", "b", "c"))                                             │
├──────────────────────────────────────┤
│Public Sub 関数(ByVal 引数 As Variant)                                      │
│    Dim 値 As Variant                                                       │
│    For Each 値 In 引数                                                     │
│        MsgBox 値                                                           │
│    Next 値                                                                 │
│End Sub                                                                     │
└──────────────────────────────────────┘
基本的に配列で渡してVariant型で受ければよい。

ParamArrayオプションを付けると引数自体を配列(可変)にすることもできる。
┌──────────────────────────────────────┐
│Call 関数("a", "b", "c")                                                    │
├──────────────────────────────────────┤
│Public Sub 関数(ParamArray 引数() As Variant)                               │
│    Dim 値 As Variant                                                       │
│    For Each 値 In 引数                                                     │
│        MsgBox 値                                                           │
│    Next 値                                                                 │
│End Sub                                                                     │
└──────────────────────────────────────┘
分類:ExcelVBA
ExcelVBA/ExcelのRange型からCells型への変換
2019年09月07日
ということでExcelVBA版を作った。いい感じ。
┌──────────────────────────────────────┐
│Public Sub セル範囲変換Range→Cells()                                       │
│    Dim theCell As Range                                                    │
│    Dim theMatches As Object, theMatch  As Object                           │
│    Dim REG As Object                                                       │
│    Set REG = CreateObject("VBScript.RegExp")                               │
│    REG.Global = False                                                      │
│    For Each theCell In Selection                                           │
│        ' Range("A1")形式を置換                                             │
│        REG.Pattern = "Range\(""([A-Z]+)(\d+)""\)"                          │
│        Do While REG.Test(theCell.Value)                                    │
│            Set theMatches = REG.Execute(theCell.Value)                     │
│            For Each theMatch In theMatches                                 │
│                theCell.Value = REG.Replace( _                              │
│                    theCell.Value, _                                        │
│               "Cells($2, " & Columns(theMatch.SubMatches(0)).Column & ")" _│
│                )                                                           │
│            Next theMatch                                                   │
│        Loop                                                                │
│        ' Range("A1:B2")形式を置換                                          │
│        REG.Pattern = "Range\(""([A-Z]+)(\d+):([A-Z]+)(\d+)""\)"            │
│        Do While REG.Test(theCell.Value)                                    │
│            Set theMatches = REG.Execute(theCell.Value)                     │
│            For Each theMatch In theMatches                                 │
│                theCell.Value = REG.Replace( _                              │
│                    theCell.Value, _                                        │
│                    "Range(" _                                              │
│      & "Cells($2, " & Columns(theMatch.SubMatches(0)).Column & ")" & ", " _│
│      & "Cells($4, " & Columns(theMatch.SubMatches(2)).Column & ")" & ")" _ │
│                )                                                           │
│            Next theMatch                                                   │
│        Loop                                                                │
│    Next theCell                                                            │
│End Sub                                                                     │
└──────────────────────────────────────┘
分類:ExcelVBA
ExcelVBA/任意の文字列たちを結合するが空文字は除く
2019年08月29日
例えば任意の複数の文字列を区切り文字で結合したい場合に
以下のようにすればよい。
┌──────────────────────────────────────┐
│CSV結果 = Join(Array(文字列1, 文字列2, 文字列3), ",")                       │
└──────────────────────────────────────┘
非常にお手軽なのだが難点があって、文字列が空文字の場合にも
「,,」みたいに結合されてしまう。(CSV的にはOKかもしれないが)

これを簡単に解決する方法はないようなので、関数を作った。
┌──────────────────────────────────────┐
│CSV結果 = 引数をCSV結合(文字列1, 文字列2, 文字列3)                          │
├──────────────────────────────────────┤
│Public Function 引数をCSV結合(ParamArray 配列()) As String                  │
│    Dim 結果 As Variant, 値 As Variant                                      │
│    For Each 値 In 配列                                                     │
│        If 値 <> "" Then                                                    │
│            Call 配列末尾追加(結果, 値)                                     │
│        End If                                                              │
│    Next 値                                                                 │
│    If IsArray(結果) Then                                                   │
│        引数をCSV結合 = Join(結果, ",")                                     │
│    Else                                                                    │
│        引数をCSV結合 = ""                                                  │
│    End If                                                                  │
│End Function                                                                │
├──────────────────────────────────────┤
│Private Sub 配列末尾追加(ByRef 配列 As Variant, _                           │
│                         ByVal 追加要素 As Variant)                         │
│    On Error GoTo l_Catch                                                   │
│    If IsArray(配列) Then                                                   │
│        ReDim Preserve 配列(UBound(配列) + 1)                               │
│    Else                                                                    │
│        ReDim 配列(0)                                                       │
│    End If                                                                  │
│    配列(UBound(配列)) = 追加要素                                           │
│    Exit Sub                                                                │
│l_Catch:                                                                    │
│    ReDim 配列(0)                                                           │
│    配列(UBound(配列)) = 追加要素                                           │
│End Sub                                                                     │
└──────────────────────────────────────┘
分類:ExcelVBA
前へ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 … 27 次へ