カテゴリー: プログラミング

PCでのプログラミングやプログラム言語について、調べた内容や経験したことについて、ダラダラと持論を書いていければと思います

  • VBScriptでUAC回避とプロセス管理!実践的な使い方

    VBScriptでUAC回避とプロセス管理!実践的な使い方

    ちょっと、記事にするほどでもないのですが、VBScriptを勉強したので覚書として残します

    ■呼び出し方法

    ・BATファイルからVBScriptを起動する

    BAT (Batchfile)
    echo off
    %~d0
    cd %~d0%~p0
    cd
    cscript /nologo test.vbs
    pause

    管理者権限でBATファイルを実行すると、パスがSystemフォルダになってしまうので、それを避けるために、呼び出し前にcdしています

    ■UACの回避

    ・Shell.ApplicationでExeを起動する

    VB
    Option Explicit
    ' 引数がない場合、Script自身を再度、管理者権限で実行する
    If Wscript.Arguments.Count = 0 Then
        ' 管理者として実行
        AppExecute("wscript.exe", WScript.ScriptFullName & " runas", "runas", 1)
        WScript.Quit
    End If
    '==============================================================
    ' これ以降に管理者権限で実行したい処理を記載する
    '==============================================================
    ' メモ帳を管理者権限で実行
    AppExecute("notepad.exe", "", "open", 1)
    WScript.Quit
    '==============================================================
    ' "Shell.Application"のShellExecuteメソッド
    '==============================================================
    Sub AppExecute(appPath, appArgs, appOpe, appShow)
        Dim shell
        Set shell = Wscript.CreateObject("Shell.Application")
        
        ' appOpe
        'edit   :エディタを起動し、編集用にドキュメントを開きます。
        'find   :指定されたディレクトリから検索を開始します。
        'open   :アプリケーションを起動します。このファイルが実行可能ファイルでない場合、関連するアプリケーションが起動されます。
        'print  :ドキュメントファイルを印刷します。
        'properties :オブジェクトのプロパティを表示します。
        'runas  :管理者としてアプリケーションを起動します。
        ' 対象のEXEを起動します。
        shell.ShellExecute """" & appPath & """", appArgs, "", appOpe, appShow
        Set shell = Nothing
    End Sub

    ShellExecuteメソッドでスクリプト自信を”runas”指定して起動することで、管理者権限で実行させることができるので、そのあとに起動するExeは全て管理者権限での実行となる

    ■実行中プロセス

    ・WMIでプロセス一覧を取得する

    VB
    Option Explicit
    Dim ret
    ' メモ帳が実行しているかを取得する
    ret = ExistsProcess("notepad.exe")
    If (ret = True) Then
        WScript.Echo "実行中です。"
    Else
        WScript.Echo "未実行です。"
    End If
    WScript.Quit
    '==============================================================
    ' WMIで実行中のプロセスを取得する
    '==============================================================
    Function ExistsProcess(targetExeName)
        ' WMIにて使用する各種オブジェクトを定義・生成する。
        Dim oClassSet
        Dim oClass
        Dim oLocator
        Dim oService
        Dim ret
        ret = False
        Set oLocator = WScript.CreateObject("WbemScripting.SWbemLocator")
        Set oService = oLocator.ConnectServer
        Set oClassSet = oService.ExecQuery("Select * From Win32_Process Where Description = '" & targetExeName & "'")
        
        If oClassSet.Count > 0 Then
            ' コレクションを解析する。
            For Each oClass In oClassSet
                ' http://www.wmifun.net/library/win32_process.html
                Wscript.Echo oClass.Handle & ":" & oClass.Description & ":" & oClass.CommandLine
                If targetExeName = oClass.Description Then
                    ret = True
                End If
            Next
            
        End If
        Set oClassSet = Nothing
        Set oClass = Nothing
        Set oService = Nothing
        Set oLocator = Nothing
        ExistsProcess = ret
    End Function

    「If oClassSet.Count > 0 Then」の時点で、「ret = True」でいいんですけどね

    ■プロセスの終了を待つ

    ・WScript.ShellのRunメソッドで終了を待つ

    VB
    Option Explicit
    ' メモ帳の終了を待つ
    ShellRun("notepad.exe", "", 1, True)
    WScript.Echo "終了しました。"
    WScript.Quit
    '==============================================================
    ' 指定したEXEを起動します。
    '==============================================================
    Sub ShellRun(runPath, runArgs, runShow, runWait)
        Dim shell
        Set shell = Wscript.CreateObject("WScript.Shell")
        
        ' runWait : 起動したコマンドの終了待ち
        'True	:待つ
        'False	:待たない
        ' 対象のEXEを起動します。
        shell.Run """" & runPath & """ " & runArgs, runShow, runWait
        Set shell = Nothing
    End Sub

    Runメソッドを使用すると起動したプロセスの終了を待たせることができます

    ■標準出力を取得する

    ・WScript.ShellのExecメソッドで出力を取得する

    VB
    Option Explicit
    Dim sOut, sErr
    ' メモ帳を管理者権限で実行
    ShellExec("cmd /C dir", sOut, sErr)
    WScript.Echo "StdOut : " & sOut
    WScript.Echo "StdErr : " & sErr
    WScript.Quit
    '==============================================================
    ' "WScript.Shell"のExecメソッド
    '==============================================================
    Sub ShellExec(command, sOut, sErr)
        Dim shell, oExec, stdOut, stdErr
        Set shell = Wscript.CreateObject("WScript.Shell")
        
        Set oExec = shell.Exec(command)
        ' ここでExecの終了を待つ(oExec.statusを見る)
        Set stdOut = oExec.StdOut
        Set stdErr = oExec.StdErr
        ' 
        sOut = stdOut.ReadAll()
        sErr = stdErr.ReadAll()
        Set stdErr = Nothing
        Set stdOut = Nothing
        Set oExec = Nothing
        Set shell = Nothing
        
    End Sub

    Execメソッドでは標準出力や標準エラー出力を取得することができます

    ■最後に

    VBScriptでできるExe実行の方法をいくつか調べたので記載しました

    Excelマクロだと、マクロの実行中に他のExcelが動かせないので、VBScriptで処理させるのも仕事の効率化につながります!

    ファイルの存在チェック等と合わせて処理を作れば、夜間バッチのような処理も実現可能ですね

    ではでは

  • プログラマーの素質とは?仕事の考え方と使い方【初心者】

    わしはなぜ、プログラマーになったのだろうか?

    スポーツ選手でも歌手でも、お笑い芸人でもなく、普通のサラリーマンだ

    その中でも、プログラマー!?

    なぜだろう?

    ■プログラマーとは?

    当然だが、アプリやシステムをコンピュータ言語を使って開発する仕事をするのが、プログラマーなのだが・・

    コンピュータ言語?プログラミング言語、と言われるものは、たくさんある

    • C、C++
    • VB、VC、C#
    • java、jQuery
    • Ruby
    • PHP
    • Python
    • SWIFT、Objective-C
    • HTML、CSS

    本来プログラマーたるや、どんな言語でも開発できるべきだと思う!

    しかしながら、特定の言語に特化したプログラマーが増えているのが現実で、それでも彼らはわしと同じプログラマーと呼ばれる

    ま、そういうわしもRubyやPythonについては、ほぼソースを見たことがある、程度なのだが

    それでもその言語でプログラムを書けと言われれば、かける自信がある!

    それでこそ、プログラマーだろ!?と思っている

    ・上流と下流

    システム開発の仕事は、以下のような工程が主な流れになる

    • 要件定義
    • 設計
    • 開発
    • テスト

    要件定義や設計は、SE(システムエンジニア)が行う上流フェーズ、開発やテストは、PG(プログラマー)が行う下流フェーズと分けられる

    そしてこれらの工程を統括し、スケジュールの管理等を行うのが、PM(プロジェクトマネージャー)ですね

    そして、社会にでれば、一般的な流れとしては、PG→SE→PMという流れでキャリアアップしていくのですが・・

    オフショアやニアショアが多くなるご時世で、PGの価値がかなり低く見積もられてしまうのが現実です!

    ・システム開発工程

    工程についてもう少し詳しく見ていきます

    先ほどは、4つだけ挙げましたが、本来のシステム開発の工程というのはたくさんあります

    一般的なのは、ウォーターフォールモデルといって、これくらいの工程かな?

    1. 要件定義
    2. 外部設計
    3. 内部設計
    4. プログラミング
    5. 単体テスト
    6. 結合テスト
    7. システムテスト
    8. 運用テスト
    9. システム移行
    10. 運用・保守

    結構ありますよね?
    これを順番に行っていった結果、9番、10番でシステムが稼働します

    ・役割分担

    システム開発は沢山の工程があり、それを複数人で作成していくために、各工程は役割分担されています

    上記の工程の場合、PGが担当するのは、4番と5番(本当は4番)だけなのです!

    5番の単体テストは、3番の内部設計の内容をテストするので、テスト項目(何をどのようにテストするかを示す資料)は、SEが担当するのですが・・

    開発スケジュールがタイトになってくると、この3番よりも4番のプログラミングが先行し、設計書が後追いで作成されることが多くなります(あってはならないはずですが・・)

    結果として、5番を行うためにPGが3番をほとんど作ることになるのです!

    4番のプログラミングの結果として、3番の内部設計通り作成できているかを5番の単体テストで行うのです

    なのに、3番と5番をプログラミングを行ったPGがやってしまったら、プログラミングによる結果が正解で、そのためのテストを実施することになってしまいます

    システムの不具合が発生したなんて言葉を耳にします

    この不具合の大きな原因は、PGのプログラムミスと思われがちです

    でも実際には、SEが設計書を書かず、設計通りに動いていることを確認できていないから起きています

    それを結局、SEが自分の身を守るために、PGのプログラミングとテストミス(設計理解不足)とされてしまっているのです

    ※個人の感想です

    キャリアアップの流れを見ても、PGよりSEの方がより上なのだと思われるのは仕方ないことだが・・

    PGの価値を甘く見ていないですか!?

    昨今、上で書いた通り、仕事のできないSEがはびこっている!w

    設計書もなく、画面デザインは作ったから、あとは、こんな風に動かして欲しいとか、口頭で説明してくるSEもいる

    どんなに優れたPGがプログラミングを行っても設計書がプアなシステムがまともに動くわけがない!

    自分たちの責任逃れのために、PGに全ての責任を押し付けるブラックSEどもめ!www

    どんなに優れたPMが仕切っていても、優れたSEが設計していても、出来上がるシステムが不具合だらけではそのシステムは使い物にならないんです!

    そのために必要なのは、ブラックSEではなく、「品質の高い開発ができるPGの存在」だと、わしは思うのです!

    まぁ、どれだけ品質の高い開発をしていても、たった一度の不具合で、いつまでもネチネチと言ってくるブラックSEがいる!

    ○○ハラスメントだろ!?とも思うが・・

    なぜ、こんなSEより、PGが下に扱われるのか、この世の中がわしには理解できんw

    どんなにキャリアアップしようが、仕事のできないブラックSEなど下の下だぜぇー!w

    この業界は、本当にくだらない仕組みが蔓延っていやがる

    ■素質とは

    これも個人の感想でしかないのだけれど、人が生まれ持ったものを素質と言うのかもしれないが

    プログラマーに必要なものは、そんな持ち合わせたものだけではないと思う

    「探求心」と「向上心」

    これをどれだけ持ち続けられるかだ!

    と、わしは思う

    ■最後に

    そんな世界でも、なぜプログラマーをやっているのだろうか?

    それは、モノづくりをすることが好きだから

    ただそれだけしかない

    自分の手で入力したソースコードが、自分の思い描いた通りに、動いてくれること

    これが凄く楽しいのですw

    ではでは

  • Excel VBAオブジェクトモデルを理解する使い方【初心者】

    Excel VBAオブジェクトモデルを理解する使い方【初心者】

    Workbookオブジェクトに関する内容を書いていて、ふと、肝心な話を書いていなかったな!ってことに気が付いたのですw

    それは何ぞや!?というと、それこそが、そ!オブジェクトモデルについてです!

    ■オブジェクトモデル

    Excelとか、VBAに限った話ではないのですが、プログラム言語の多くは、オブジェクトが階層構造で作られています

    こういう階層のことをアプリケーションの「オブジェクトモデル」というんですねーw

    (プログラムを勉強したことがある人や、オブジェクト指向プログラミングなんて言葉を聞いたことがある人にとっては、既知の話ですが)

    ExcelなどのOffice VBAでも当然のことながら、この階層構造で作られた「オブジェクトモデル」なのです!

    ・オブジェクトとオブジェクトモデル

    言葉に注意ですが、「オブジェクト」と「オブジェクトモデル」は別のものです!

    • 「オブジェクト」は、(例えば「Workbookを定義した」)『クラスから作成(インスタンス化)したモノ』を指します(「Workbookオブジェクト」と呼ぶ)
    • 「オブジェクトモデル」は、(上手く言えませんが)アプリケーションにおける『階層構造』がどのように作られているのかを示す『概念図』のことを指します

    ますます判りにくくなりましたけどwww

    ま、「階層構造」≒「オブジェクトモデル」で問題なし!(ホンマか!?w)

    ・クラス

    ちなみに、突然「クラス」って言葉も出てきましたが、言葉としては「クラス」と「オブジェクト」が同じように使われることもありますが、

    先にも書いた通り『「クラス」から作成されるのが「オブジェクト」』です

    (多少語弊はありますが)「Workbookクラス」は(基本的に)1つですが、「Workbookオブジェクト」は複数作れます

    で「クラス」ってのは、メソッドやプロパティなどを定義した設計図(テンプレートとも言われる)のようなものです

    「クラス」が平面(設計図)で、「オブジェクト」が立体(製造物)というイメージです(?)

    ■VBAの概念図

    なんてものは、Microsoftにでも聞いてくださいw

    というわけで、ここでは、ざっくりとExcelでのVBAの階層構造について触れようと思います

    Excelの中(メンバー)には、ApplicationやWorkbooks、Range、Fontなどのクラスがたくさん用意(定義)されています

    このクラスがどのように階層化されているのか、よく使うクラスをよく使う階層でサラッと紹介しておきますw

    ・階層

    「Excel.Application」が「Excel」のトップレベル!

    1. 最初の階層として、【アプリケーション】があります
    2. その下に【ファイル】を表す「Workbooks (Workbook)」
    3. 更にその下に、「Workbook」単位で以下があります
      • 【シート】を表す「Sheets」
      • 【スタイル】を表す「Styles (Style)」
      • 【名前定義】を表す「Names (Name)」

    ※「Sheets」は「Worksheets (Worksheet)」と「Charts (Chart))」で構成

    更に、その下に・・・と結構続きますので、大変ですねw

    ・構造図(簡易)

    文章だと判りずらいので、Tree階層で構造図を表現してみますw

    (※主にコレクションを中心に記載しています)

    VB
    EXCEL
      └─Application
          └─Workbooks (★)
              ├─Names (☆)
              ├─Sheets
              │  ├─Charts
              │  │  ├─Axes
              │  │  ├─ChartGroups
              │  │  ├─DataTable
              │  │  └─Shapes
              │  └─Worksheets (★)
              │      ├─Comments (☆)
              │      ├─Names (☆)
              │      └─Range (★)
              │          ├─Areas
              │          ├─Borders (★)
              │          ├─Columns (☆)
              │          ├─Hyperlinks (☆)
              │          └─Rows (☆)
              └─Styles (☆)
    

    「Charts」や「Worksheets」の下層は個人の見解ですw

    記載していないのも多数あります(書ききれないw)

    まぁ、クラスの構造図とはこんな風に『階層化で表現できる!』

    ・・とそんな風に判ってもらえれば良いかと思いまーす(かなり適当w)

    ※上図の星マークは以下のレベルです

    ★:勉強した、☆:勉強したい

    少しずつですが、随時、記事にしていこうと思います!

    ■最後に

    このオブジェクトモデルの概念を知っているのと知っていないとでは、VBAプログラミングを行う上で影響が出てくると思っています(たぶん)

    VBエディタでプログラミングをしていると、「Excel.」と『.』(ドット、ピリオド)を書くと、配下のオブジェクトなどが自動で出てきてくれます

    (これは参照設定が必要な場合もありますw)

    それらやクラスのメンバーを見ていると、至る所の階層に同じクラスが出現するので、正確な階層構造を知るのは非常に困難です(Microsoftに聞いてー!)

    そのため、個人によっては、異なる階層構造を主張する人もいると思いますし、わしが見つけられなかっただけで、正式なオブジェクトモデル図があるかも知れません!w

    ここの記載内容が、『個人の見解であること』を十分にご理解ください

    ではでは

  • VBAコードの基礎と使い方:代入・分岐・繰り返しを解説

    VBAコードの基礎と使い方:代入・分岐・繰り返しを解説

    【環境】Windows 10 Pro 64bit、Excel for Office 365

    プログラムの基礎と言ったら分岐と繰り返しと・・・と、なんだ?w

    まー、そんなことは、どこかの偉い人が書いた文献でも読んで学んでください!

    ざっくりと、プログラムを知らない、難しい?大変?なんですよねー?って、思ってる人に、簡単だよ!って教えるためのブレークタイムのような記事を書きますw

    念のため、先に言うときますけど、ここに書かれていることは、真実ではない可能性があります

    わしの考え方ですので、ちゃんとプログラムを知りたい人は、ちゃんと勉強してくださいねー!w


    ■基本的な要素

    以下がプログラムの基礎的な要素になります!(言い切るスタイル!w)

    • 変数(プロパティ)
    • 関数(メソッド)

    たった2つ・・そんなもんさ~

    クラスだとか、オブジェクトだとか、型、列挙型、構造体、共用体、配列、引数、戻り値、ポインタ、アドレス、値渡し、参照渡しとか、色々な難しい言葉を耳にしたことがあると思います

    でもね!肝になるのは「変数」と「関数」だけなんです!

    「変数」を「関数」に渡すには【引数】を使うってだけで、【構造体】だって「変数」の組織だった集まりなわけでw

    「変数」って何?「関数」って何?がわかってれば、プログラムなんてできるんですよー!(たぶんねw)

    例)1+1=2

    「変数」と「変数」を「関数」で処理したら新しい「変数」になるんですよー!的な?w

    プログラムなんて、それの積み重ねですよ!

    そりゃ、品質のいいプログラムを短時間で作成しようとしたら、センスだの経験だのって、色々必要なものはあるでしょうけど、そんなもんは、別世界の話です

    ・変数とは

    「変数」ってのは、データの入れ物なんです!

    「変数」は使い方が色々あって、元のデータを入れておくものもあれば、処理が終わった後のデータを入れておくものもある

    それが、役割によって、引数だったり、戻り値だったり、配列や構造体だったり、名前や形状を変えてるだけで、要は「変数」ですw

    ・関数とは

    「関数」ってのは、データを処理するんです!

    「関数」は入力されたデータをどうにかこうにか処理して、あんな方法やこんな方法で出力するのです

    条件による分岐や繰り返しを経て、計算や代入を行って、色々と異なる方法で出力されるだけなんです


    ■VBAで代入してみる

    変数の使い方は、関数の中と外ではちょっと違います

    ・サンプルソース

    VB
    Private aaa As String
    Sub Func1()
        Dim bbb As String
        
        aaa = "AAA"
        bbb = "BBB"
        
        Call Func2(bbb)
    End Sub
    Private Sub Func2(ccc As String)
        Dim bbb As String
        
        Debug.Print "aaa = '" & aaa & "'"
        Debug.Print "bbb = '" & bbb & "'"
        Debug.Print "ccc = '" & ccc & "'"
        
    End Sub
    

    ・コード説明

    大したサンプルは書けませんが、簡単に説明します

    • 1行目:ファイル内でのみ使用できる変数
    • 3行目:ファイルの外からでも呼び出せる関数
    • 4行目:関数内でのみ使用できる変数
    • 6~7行目:変数にデータを代入
    • 9行目:変数を関数に渡して呼び出す
    • 13行目:ファイル内でのみ呼び出せる関数
    • 14行目:関数内でのみ使用できる変数
    • 16~18行目:それぞれの変数を出力

    ・出力結果

    上記のサンプルプログラムでFunc1を実行すると以下の出力が得られます

    VB
    aaa = 'AAA'
    bbb = ''
    ccc = 'BBB'

    ・出力の解説

    • 変数:aaaは、ファイル内で使用できるので、関数:Func1で代入したデータの「AAA」が、関数:Func2でも参照できます
    • 変数:bbbは、関数内でのみ使用できる変数なので、関数:Func1で代入していますが、関数:Func2ではデータは代入されていないので、空の文字列です
    • 変数:cccは、関数:Func2の引数として、関数:Func1から、変数:bbbを渡されていますので、関数:Func1で代入したデータ「BBB」が参照できます

    ■処理 – 分岐

    分岐というと条件が必要になりますが、関数で使われる処理では最も頻度がたかいでしょうか?そんな感じがします

    VBAで使用する分岐をいくつか紹介します

    ・If…Then…Elseステートメント

    基本的な条件分岐の「もし○○だったら××をする」です!

    使い方はこんな感じで、①も②も③も書き方は異なりますが、全て同じ分岐で、同じ処理結果が得られます

    VB
    Sub FuncIfElseThen(aaa As Integer)
        ' ①
        If aaa = 1 Then
            Debug.Print "aaaは1です"
            
        ElseIf aaa = 2 Then
            Debug.Print "aaaは2です"
            
        Else
            Debug.Print "aaaはそれ以外です"
            
        End If
        ' ②
        If aaa = 1 Then
            Debug.Print "aaaは1です"
            
        Else
            If aaa = 2 Then
                Debug.Print "aaaは2です"
                
            Else
                Debug.Print "aaaはそれ以外です"
                
            End If
            
        End If
        ' ③
        If aaa = 1 Then Debug.Print "aaaは1です" Else If aaa = 2 Then Debug.Print "aaaは2です" Else Debug.Print "aaaはそれ以外です"
    End Sub
    

    ③が長かったですが、これぞ「If…Then…Else」ステートメントの繰り返し!


    ※余談ですが、Ifの分岐を関数化した「IIf関数」というのもありますw

    構文は、以下の通りですが、分岐ではなくあくまでも関数ですので、解説はしません

    IIf(expr, truepart, falsepart)

    上のサンプルソースと同じ結果を得るには以下のように記載します

    VB
    Sub FuncIIf(aaa As Integer)
        Debug.Print IIf(aaa = 1, "aaaは1です", IIf(aaa = 2, "aaaは2です", "aaaはそれ以外です"))
    End Sub
    

    ・Select Case ステートメント

    もう一つの分岐としては、「Select Case」ステートメントです!

    使い方はこんな感じで、文字列を評価することも、評価に範囲や条件、変数を入れることもできます

    VB
    Sub FuncSelectCaseString(aaa As String)
        Dim bbb As String
        bbb = "GGG"
        Select Case aaa
        Case "AAA": Debug.Print "aaaは'AAA'です"
        
        Case "BBB", "CCC"
            Debug.Print "aaaは'BBB'もしくは'CCC'です"
        Case "DDD" To "FFF"
            Debug.Print "aaaは'DDD'から'FFF'の間です"
        
        Case bbb
            Debug.Print "aaaはbbbと同じです"
        Case Else
            Debug.Print "aaaはそれ以外です"
        
        End Select
    End Sub
    Sub FuncSelectCaseInteger(aaa As Integer)
        Select Case aaa
        Case 1: Debug.Print "aaaは1です"
        
        Case 2, 3
            Debug.Print "aaaは2か3です"
        
        Case 4 To 6
            Debug.Print "aaaは4~6です"
            
        Case Is >= 7, Is < 10
            Debug.Print "aaaは7~9です"
            
        Case Else
            Debug.Print "aaaはそれ以外です"
        
        End Select
    End Sub

    IfThenElseステートメントは、ElseIf毎に別々の条件をかける(評価対象を変えれる)ので、分岐回数分の評価が行われるのですが、SelectCaseステートメントは、最初に1度評価するだけで、どのCaseに一致するかで処理されます


    ■処理 – 繰り返し

    次は繰り返しですが、こちらも方法としては色々ありましてですねーw

    これもVBAで使用するものを紹介します

    ・For…Next ステートメント

    基本的な繰り返しと言えば「○○から××まで繰り返す」ですね!

    使い方はこんな感じで、繰り返す範囲や1回の繰り返しの増減値を指定できたりします

    VB
    Sub FuncForNext()
        Dim idx As Integer
        
        For idx = 0 To 10 Step 1
            Debug.Print "idx = " & idx
            
            If idx = 8 Then
                Exit For
            
            End If
        
        Next idx
        
        For idx = 10 To 0 Step -2
            Debug.Print "idx = " & idx
        Next
    End Sub
    

    条件によっては、繰り返しをやめたい場合には、「Exit For」で抜け出すことができます!

    ・For Each…Next ステートメント

    もう一つのFor・・「For Each…Next」ステートメントです!

    これは、配列やコレクションを指定して、そのグループを最初から最後まで繰り返してくれます

    使い方はこんな感じで、あえて、見慣れたFileSystemObjectを使用してみました!

    VB
    Sub FuncForEachNext(path As String, ptrn As String, data As Collection)
        Dim fl      As File   
        With New FileSystemObject
            ' pathのファイルを取得
            For Each fl In .GetFolder(path).Files
                ' ファイルパターンに一致するものだけ取り出す
                If (UCase(fl.name) Like UCase(ptrn)) Then
                    ' Fileオブジェクトをコレクションに格納
                    Call data.Add(fl)
                End If
            Next
        End With
    End Sub
    

    FilesプロパティはFileオブジェクトのコレクションですので、ForEachNextステートメントで取り出す場合、Fileオブジェクト型の変数でのみ取り出すことことができます(ちょっとだけ嘘ですがw)

    「For Each」と「In」の間の受け側の変数は、「In」の後ろの変数(コレクション)に内包された型の変数でのみ取り出せる!というのかな???

    ま、型が一致してないとダメって、怒られます!?(これも微妙に違うw)

    配列でFor Eachを使う場合、バリアント型の配列じゃないと・・

    VB
    Sub FuncForEachNextNG()
        Dim var     As String
        Dim str(3)  As String
        Dim i       As Integer
        
        For i = 0 To 3
            str(i) = Trim(i)
            
        Next i
        
        For Each var In str
            Debug.Print Trim(var)
            
        Next
    End Sub
    
    配列は型が違うと怒られる
    配列は型が違うと怒られる

    以下のように、受ける「var」をバリアント型(Variant)で定義することで受け取れますので、「バリアント型の配列」でなくても大丈夫です

    VB
    Sub FuncForEachNextOK()
        Dim var     As Variant
        Dim str(3)  As String
        Dim i       As Integer
        
        For i = 0 To 3
            str(i) = Trim(i)
            
        Next i
        
        For Each var In str
            Debug.Print Trim(var)
            
        Next
    End Sub
    

    ちなみに、FileSystemObjectのFileオブジェクトを格納したCollectionから、Fileオブジェクトを取り出すにはどうするのか!?ですが・・こうします!

    VB
    Sub FuncForEachNextCollection(data As Collection)
        Dim fl      As File
        
        For Each fl In data
            Debug.Print fl.Name
        Next
        
    End Sub
    

    Collectionの中身がFileオブジェクトなので、受け側の変数には、バリアント型 の変数、汎用オブジェクト変数や特定のオブジェクト変数が指定できるのです

    ・While…Wend ステートメント

    繰り返しは色々あるのですが、このステートメントは正直言って、あまり使いませんw

    なので、使い方は、どこぞのサンプルをほぼほぼそのまんま載せますw(怒られる?)

    VB
    Sub FuncWhileWend()
        Dim Counter
        
        Counter = 0
        
        While Counter < 5
            Counter = Counter + 1
            Debug.Print Counter
            
        Wend
        
        Debug.Print Counter
        
    End Sub
    

    Counterが5未満の間、+1の処理を繰り返すので、実行結果は・・ご想像にお任せしますw

    必ず指定回数を繰り返すので、途中で抜けるには強制的に「Exit Sub」とかすることになるので、あまりよろしくないです

    サンプルも悪いので、回数がわかっているなら、ForNextステートメントでいいですし、カウンターが必要ならなおさらForNextステートメントでしょ!?

    って、なってしまいますが、もう少し複雑な条件の間に処理を行わせるとか、もしくは複雑な条件でカウントアップするような場合には、使えるんでしょうけどね・・

    きっと次に紹介するステートメントで、より柔軟にできちゃうんですw

    ・Do…Loop ステートメント

    条件を満たすまで、処理を繰り返すことができますし、1つのステートメントですが、条件の設定が「Do」の後と「Loop」の後の2か所で設定できるので、構文が2つあるのです!

    VB
    Sub FuncDoLoop()
        Dim idx As Integer
        idx = 0
        
        Debug.Print "①"
        Do While (idx < 3)
            idx = idx + 1
            Debug.Print "idx = " & idx
        
        Loop
        
        Debug.Print "②"
        Do
            idx = idx + 1
            Debug.Print "idx = " & idx
        
        Loop While (idx < 6)
        
        Debug.Print "③"
        Do
            idx = idx + 1
            Debug.Print "idx = " & idx
            
        Loop Until (idx >= 9)
        
        Debug.Print "④"
        Do Until (idx >= 12)
            idx = idx + 1
            Debug.Print "idx = " & idx
        Loop
        Debug.Print "⑤"
        Do While (idx < 12)
            idx = idx + 1
            Debug.Print "idx = " & idx
        
        Loop
        
        Debug.Print "⑥"
        Do
            idx = idx + 1
            Debug.Print "idx = " & idx
        
        Loop While (idx < 12)
        
        Debug.Print "⑦"
        Do
            If idx > 15 Then Exit Do
            
            idx = idx + 1
            Debug.Print "idx = " & idx
        
        Loop While (idx > 12)
        
    End Sub
    

    長くなってしまいましたw

    構文的には、これと・・

    Do [{ While | Until } condition ]
    [ statements ]
    [ Exit Do ]
    [ statements ]
    Loop

    これ・・・

    Do
    [ statements ]
    [ Exit Do ]
    [ statements ]
    Loop [{ While | Until } condition ]

    ちなみに、上のサンプルの結果はこうなりますが、やりたいことが伝わりますかね?w

    VB
    
    idx = 1
    idx = 2
    idx = 3
    
    idx = 4
    idx = 5
    idx = 6
    
    idx = 7
    idx = 8
    idx = 9
    
    idx = 10
    idx = 11
    idx = 12
    
    
    idx = 13
    
    idx = 14
    idx = 15
    idx = 16

    「Do」か「Loop」のどちらに条件を書くかによって、当然ですが処理が異なり、①~④は単純に構文のパターンを網羅しただけです

    • ①:idxが3未満の間、繰り返す
    • ②:idxが6未満の間、繰り返す
    • ③:idxが9以上になるまで、繰り返す
    • ④:idxが12以上になるまで、繰り返す

    ⑤~⑥は同じ条件式でも評価されるタイミングが異なるため、ステートメントが実行されるかどうかが異なることを示しています

    • ⑤:idxが12なので、ステートメント実行前に評価され、実行されない
    • ⑥:idxが12ですが、ステートメント実行後に評価され、実行される

    ⑦は「Exit Do」で任意にステートメントを終了する(抜ける)ことができることを示しています


    ■まとめ

    そろそろ頭が痛くなる人もいるかと思いますが、これでほぼ肝心なことは全て記載したと思います!

    変数と関数、代入、分岐と繰り返しは説明したので、あとは入出力の方法だけなのですが、それは多種多様なので、今後どこかのプログラム作成中に出てくるので、気付いてくださいw

    ■次回

    次回こそファイル一覧の続きをやります!

    ではでは

  • Excel自動化で作業効率アップ!VBAの使い方【初心者】

    Excel自動化で作業効率アップ!VBAの使い方【初心者】

    【環境】Windows 10 Pro 64bit、Excel for Office 365

    仕事の作業効率をあげるために、Excelによる作業の自動化について考えてみることにしました(唐突ですがw)

    ■自動化の目的

    Excelの作業効率を上げるために行うべきことは、ファイル(Workbook)単位ではなく、シート(Worksheet)単位での自動化を行うことです!

    『えっ!?ファイル全部じゃないの!?』『ファイルは沢山あるのよ!?』とお思いでしょうが、よく考えてください

    一般的に1つのファイルは、1つの資料を意味していますから、その1つの資料には様々な形式のシートが含まれています!

    ですよね?

    その数あるシートの中から必要なシートを選別して自動で処理することが大切なのです

    ファイルにターゲットを絞って、自動化してもそのファイルにしか対応できないのです

    ファイルが自動で処理する対象のファイルかを判断するのは大変ですが、シート単位の判断なら簡単なのです!

    更に、ファイルの中のシートが変われば、自動化の処理もそれに追従しなければならないですし、そのファイルが暖簾分けした日にゃ!?

    自動化の処理も暖簾分け・・って、そりゃーもー大変!w

    これらのことを踏まえて、ファイルをターゲットにした自動化は、全く効率がよくありません!

    もしあなたが、『作業を自動化しているのに効率が悪い』と感じているのなら、

    最初に確認すべきことは、『その自動化はシート単位で自動化できているのか!?』です!

    そして、おそらく、その答えは『否』、ファイルをターゲットにした自動化だと思われます

    ■あるべき姿

    どんなファイルであろうと、条件を満たすシートがある限り繰り返させることができるのが、自動化の本来の形であると考えます

    例えば、1つのファイルにシートが増えたとしても、そのシートが条件を満たさないのであれば、自動化の処理は何も変わらないです

    条件を満たした場合で、1つのファイルの中に複数のシートが条件を満たすことになったとしても、対象となるシートが増えただけなので、自動化の処理は何も対応する必要がないのです!

    暖簾分けしようが、シートが消されようが、自動化の処理には何も関係ない

    だからこそ!シート単位で自動化を行うことが大切なのです!

    ・注意点

    シートをターゲットとせよ!って書くと、対象のシートを探すためにファイル毎にシートを探しながら、シート一覧を作ってしまいがちですが、それは間違いです!

    何よりもまずは、シートではなく、ファイル一覧を作成してください!

    そしてそのファイルの中から、シートを検索したいファイルを選んでからシート一覧を作成する、二段階での作成を行うようにしてください!

    『わざわざ二段階にするのは面倒だ!』、『自動化なら一気にシート一覧を作った方が楽ではないか!?』と思いがちです

    でも、この二段階にすることは非常に大事なことなのです

    もし1つフォルダに複数ファイルがあって、全て対象シートを持つファイルだと判っていたとしても、二段階にすることをお勧めします!

    理由は1つ!そのフォルダに1ファイル、後から追加になった場合に、全てのファイルを対象として、処理をやりなおすのか、追加されたファイルだけを行うのか!?を選べるからです

    ※普通は、後から追加になるファイルはフォルダを分けることが考えられますが、自動化はシステムが出来上がってから後付けで行うことが多いので、自動化側でシステムの補填をしてあげる必要があるのですw

    ■Excelでの自動化

    Excelでの自動化と言って思い付くものはこんなとこですかね?

    • Excelの操作を記録するマクロ
    • マクロを集めたアドイン
    • Excel VBAによるプログラミング

    単純な繰り返しの作業をマクロを使って、自動的に行うことはよくあることですが、馴染みのない方も多いかも知れませんが、ExcelにはVisual Basic Editor が付いており、VBA(Visual Basic for Applications)によるプログラミングを行うことで、ファイルやアプリケーションの操作を行うこともExcelではできてしまうのです!

    ・Excelの役割

    Excelは表計算ソフトではありますが、罫線を利用することで、定型の書類として使用されることもしばしばあります

    Excelでは以下のようなこともできるので、書類としても重宝されている訳です

    • 入力する文字や数字を制限
    • 入力値に合わせて文字列を表示
    • 入力値を使用した複雑な計算
    • リストデータをグラフ化
    • etc…

    このような場合には、Excelが持っている機能(メニューにあるもの)や関数でできてしまうのですが、これを大量に行わなければならないとき、そんな時こそVBAでプログラミングを行って自動化してしまうのです!

    ■VBAプログラミングを始める

    プログラミングと聞くと、慣れていない人は、難しいのではないかと思うかもしれませんけど、ExcelでVBAを始めるのは、比較的簡単にできてしまいます

    1. [開発] タブを表示する
    2. [開発] タブからVisual Basic Editorを起動する

    「1.[開発] タブを表示する」はExcelの[ファイル] – [オプション]からExcelのオプションを開き、「リボンのユーザー設定」でメインタブにある「開発」にチェックを付けます

    Office 365 「リボンのユーザー設定」
    Office 365 「リボンのユーザー設定」

    「2.[開発] タブからVisual Basic Editorを起動する」は表示した開発タブの「Visual Basic」をクリックするだけです

    開発タブ
    開発タブ

    これでVisual Baseic Editor(Micorosoft Visual Basic for Applications)が起動します

    Visual Baseic Editor
    Visual Baseic Editor

    [開発] – [マクロの記録]を使って、記録されたマクロもこの Visual Baseic Editor で表示し、編集することができます

    ■マクロの記録

    マクロの記録をすると、どのように Visual Baseic Editor に記載されるのかをみてみましょう!

    1. [開発] – [マクロの記録]をクリック
    2. 「マクロの記録」画面で「OK」ボタンをクリック
    3. セル[A1]に『Hello World』と入力して[Enter]キーを押下する
    4. [開発] – [記録終了]をクリック
    「マクロの記録」画面
    「マクロの記録」画面

    こんな感じに標準モジュールに「Module 1」が追加され、以下のように「Macro1」が記載されています

    Visual Baseic Editor に追加されたマクロ
    Visual Baseic Editor に追加されたマクロ

    つまり、マクロの中身はExcel VBAのプログラミング(ソースコード)なのです!(何か色々なことを割愛したような気がするが・・w)

    ・マクロの中身を見てみる

    実際に作成されたソースコードを見ていきましょう

    VB
    Sub Macro1()
    '
    ' Macro1 Macro
    '
    '
        ActiveCell.FormulaR1C1 = "Hello World"
        Range("A2").Select
    End Sub
    

    1行目「Sub Macro1()」

    これはマクロ実行時に出てくるマクロ名「Macro1」を実行した際に、呼び出される関数の定義(宣言)になります

    「Sub」というのは、「関数の戻り値がない」ということを意味しています

    ※反対に「関数が戻り値を返す」のは、「Function」と記載し、戻り値の型を行の後ろに追加します(「型」については、多種多様なため、種類やその説明については割愛しますw)

    次に、「’」で始まる行が続いていますが、これはコメントですので、プログラムの実行には関係しません

    ただし、ここに情報(メモ)を記載することで、後からこれを見て、この関数が何をするのかを判断することができます

    ※ちなみに、わしはコメント推奨派ですw

    7行目「ActiveCell.FormulaR1C1 = "Hello World"

    これは現在のアクティブなセルに数式を R1C1 参照形式で指定して、『Hello World』と入力することを意味します

    8行目「Range("A2").Select

    これは[Enter]キーでセルが[A2]に移動したことで、[A2]を選択したということを意味します

    9行目「End Sub」

    これは関数(Sub)の終わりを意味します

    ※「Function」の終わりは「End Functrion」となります

    わずか数行ですが、これも立派なVBAによるプログラミングなのです!

    ■アドイン

    単純に考える場合、アドインとはマクロ登録した関数をまとめて、誰でも使えるように、ファイルに抽出したものだと考えてもらっておいて良いかとw

    よく利用するちょっとした関数は、多くのシートが入ったExcelファイル等を複数の作業者で扱う場合に、以下のような関数を作成して、アドインで配布しておきます

    • 表示倍率を100%に統一
    • アクティブセルを[A1]に設定
    • ドキュメントのプロパティから個人情報を削除
    • 余分なスタイルの削除
    • リンクの切れた参照や名前定義を削除

    そうすると、保存するときには、必ず、上記の関数を通してから保存してもらうようにすることで、個々の作業者が作業しやすくなったりします

    ※実際には、Excel等にオリジナルのリボンを追加することができるので、作業に特化したリボンを作成して、担当者に配布することが理想な気はしますが、これを開発するのは、現在のOffice365では結構面倒ですので、今は割愛しますw(いつかは開発していきたいなー)

    ■VBAプログラミング

    というわけで!・・・?w

    「マクロの記録」がVBAだ!と勘違いさせて終わりそうなので、訂正しておきますが、「マクロの記録」がイコールではなく、Visual Baseic Editor を使用して、関数を作成していくことがVBAプログラミングなのです!

    自動化を考えると題してはいましたが、考えるというよりは、VBAを使って自動化を行っていきます!という決意表明となりますw

    この先、VBAで自動化を行っていく際に出てくる問題等を忘備録として残していこうと思いますが、間違ってたら・・ごめんなさいm(_ _)m

    Excelでよくやりがちな、CSVファイルのデータをExcelに取り込んで、集計したりという処理を実際に自動化のツールを作りながら、記事にしていけたらと思います

    というわけで、いつかきっと、ちゃんとVBAプログラミングの記事を書いていきます!

    またよろしくお願いしやーーーっす!

    ではでは