• 「VBScriptでクリップボードに送る」の問題への対策

    2016-09-30 22:37
    前回の記事では、VBScriptからクリップボードへ送る方法と、その場合の問題点として「環境依存文字が文字化けする」といった話をしました。

    今回はその問題点を"Visual Basic .NET"を使って無理矢理解決していきます。

    "Visual Basic .NET"とは

    "Visual Basic .NET"(以降VB.NET)は、"Visual Basic"というプログラミング言語の見た目を維持しつつ、土台部分を総入れ替えして再設計された言語となります。
    名前自体は"Visual Basic"のままですが、区別をするため".NET"を付けて呼ばれます(".NET Framwork"という土台を使っているため、略して".NET"となります)。

    VB.NETの特長としては"Visual Basic"とよく似た書き方ができる点、そして追加のソフト無しでコンパイル(プログラムの作成)が出来る点となります(端末によってはコンパイル不可)。

    そしてVBScript(Visual Basic Scripting Edition)やVBA(Visual Basic for Application)は先頭の"VB"の文字の通り、"Visual Basic"というプログラミング言語を元にしています。

    つまりVBAなどの知識があれば、少し勉強するだけで簡単なVB.NETのプログラムを作成することができます。


    それでは、例として前回の記事のサンプルのをVB.NETの記述に変換してみたいと思います。

    VBScript→VB.NET

    ① 入れ物の作成

    まずはコードを記述する場所を作成します。
    テキストファイルを作成して、拡張子を".vb"に変更します。
    VBScriptでは".vbs"ファイル、VBAではOfficeファイルにあたります。

    ② 標準モジュールの作成

    ".vb"ファイルを作成したらテキストエディタで開いて以下のように記述します。
    Module SendToClipboard 'モジュール名
    End Module
    VBAで標準モジュールを挿入して、名前を変更した状態です。

    ③ エントリーポイントの作成

    エントリーポイントというのは「起動したとき最初に動作するプロシージャ」のことです。
    VBScriptのべた書きした部分にあたります。
    標準だと"Main"という名前のプロシージャがエントリーポイントとして認識されます。
    ②にサブルーチン"Main"を追加すると以下のようになります。
    Module SendToClipboard 'モジュール名
    Sub Main()
    End Sub
    End Module

    ④ コマンドライン引数を受け取る

    VBScriptでは"Wscript.Arguments"からコマンドライン引数を受け取ることができました。
    VB.NETでもコマンドライン引数を受け取ることができます。
    いくつか記述方法がありますが今回は一番シンプルな方法として、「エントリーポイントの引数に設定する」方法とします。
    ③に追加すると以下のようになります。
    Module SendToClipboard 'モジュール名
    Sub Main(Arguments() As String)
    End Sub
    End Module
    "Main"プロシージャに"Arguments"という名前のString型配列の引数を追加しました。
    こうすることで、コマンドライン引数を半角スペースで分割したString型配列をプロシージャ内で使用することができます。

    ⑤ 引数の数をチェックする

    ここからはプロシージャの中身を確認していきます。
    まずはVBScriptの以下の記述を書き換えます。
    '異常処理:引数なし
    Dim argsCnt 'As Integer
    argsCnt = Wscript.Arguments.Count - 1
    If argsCnt = -1 Then
    Call MsgBox("ファイルをドロップしてください", vbExclamation, MSG_TITLE)
    Call Wscript.Quit
    End If
    引数が無かったら終了するという処理です。

    上記処理は以下のように記述することができます。
    'Visual Basic風の記述
    If UBound(Arguments) = -1 Then '引数が0個だと-1、1個だと0
    Call MsgBox("ファイルをドロップしてください", vbExclamation, MSG_TITLE) '変更無し
    End
    End If


    '.NET多めの記述(備考
    If Arguments.Length = 0 Then '引数が0個だと0、1個だと1
    System.Windows.Forms.MessageBox.Show("ファイルをドロップしてください", MSG_TITLE,MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
    End
    End If
    今回の場合、引数が配列に入っているので配列の添え字の上限をとる"Ubound"で数を確認することができます。
    "MsgBox"関数は書き換え無しで、そのまま動作します。
    終了処理の"Wscript.Quit"は"End"ステートメント、今回の場合は"Exit Sub"でも問題ないです。

    ⑥ クリップボードに送る

    前回のサンプルではこの後"Join"用に引数を配列に入れていましたが、今回はすでに配列に入っていますのでクリップボードへ送る動作を確認していきます。

    では、VBScriptの以下の記述を書き換えます。
    'クリップボードに送る(コピーする)文字列作成
    Dim cpText 'As String
    Dim myDel 'As String
    myDel = vbCrLf
    cpText = Join(argsArray, myDel)

    With CreateObject("Wscript.Shell")
    With .Exec(CLIP)
    Call .StdIn.Write(cpText)
    End With '.Exec(CLIP)
    '~
    End With 'CreateObject("Wscript.Shell")
    なお、上の記述では~で隠れている部分の"Wscript.Shell"のPopupメソッドを使った記述はVB.NET単体では記述が難しいので、完全再現するなら「CreateObject("Wscript.Shell")」で
    "Wscript.Shell"をインスタンスする必要があります。

    'Visual Basic風の記述
    Dim myDel As String = vbCrLf 'VB.NETでは宣言と同時に代入可能
    Dim cpText As String = Join(Arguments, myDel)


    'クリップボードに送る
    System.Windows.Forms.Clipboard.SetText(cpText)



    '.NET多めの記述(備考)
    Dim myDel As String = ControlChars.CrLf
    Dim cpText As String = Arguments.Join(myDel)

    'クリップボードに送る
    System.Windows.Forms.Clipboard.SetText(cpText)

    以下の部分が.NETからクリップボードにテキストを送る記述となります。
    System.Windows.Forms.Clipboard.SetText(cpText)
    これを分解すると
    "System.Windows.Forms"名前空間の(VBAでの参照設定のようなもの)
    "Clipboard"オブジェクトの
    "SetText"メソッドを呼び出している形となります。

    ⑦ ソースまとめ

    ここまで記述を統合してひとまとめにしたものが以下になります(一部宣言も整理しています)。

    Module SendToClipboard
    Sub Main(Arguments() As String)
    Const MSG_TITLE As String = "クリップボードにコピー"

    '異常処理:引数なし
    If UBound(Arguments) = -1 Then
    MsgBox("ファイルをドロップしてください", vbExclamation, MSG_TITLE)
    Exit Sub
    End If

    'クリップボードに送る
    System.Windows.Forms.Clipboard.SetText(Join(Arguments, vbCrLf))
    MsgBox("コピーが完了しました", vbInformation, MSG_TITLE)

    End Sub
    End Module

    ここまで作成できたらソースの作成は終了です。

    ⑧ コンパイル

    ソースが出来上がったら、プログラムとして使える形にコンパイルしてみましょう。

    まずはVB.NETのコンパイラの場所を確認します。
    Winodowsのインストールされているドライブから、"Windows"、"Microsoft.NET"、"Framework64(またはFramework)"まで辿ります。
    例:C:\Windows\Microsoft.NET\Framework64

    その中に"v数字"みたいなフォルダがあるはずなので、一番数字が大きなフォルダに入ります。
    フォルダの中にたくさんファイルがありますが、その中から"vbc.exe"というファイルを探します。"vbc.exe"がVB.NET用のコンパイラとなります。

    無事見つかったらコマンドプロンプトを開いて、コマンドプロンプト上に"vbc.exe"をドロップします。
    ドロップすると"vbc.exe"のフルパスが入るので、半角スペースを入れて今度はソースファイルをコマンドプロンプトにドロップします。

    >"~vbc.exe" (半角スペース) "ソースファイルのフルパス"
    となったらEnterを押すとコンパイルが行われます。
    記述に問題がある場合はメッセージが出てくるので、それに応じて修正をしてください。
    コンパイルが完了すると、ソースファイルのあるフォルダに同じ名前の".exe"ファイルが作成されます。
    あとは、".exe"ファイル上にファイルをドロップすれば、そのパスがコピーされます。

    最後に

    ここまでざっくりですが、簡単なVB.NETプログラム作成の流れを確認してきました。
    ここまで読んでいただいた方なら、基本的な記述はVBAとほぼ同様に出来るのがわかるかと思います。
    当然、それだけではダメな部分はありますが思ったよりも難しくないと思っていただければ幸いです。

    VB.NETではやや注意が必要ですがCOMオブジェクトが扱えますし、.NETの機能も利用できるため、VBAなどよりもできる事が広がります。
    また、PowerShellも.NETをベースにしていますのでそちらも併せて勉強すると.NETについての知識を身につけやすいと思います。
  • 広告
  • VBScriptでクリップボードに送る

    2016-09-25 01:09

    VBScriptでクリップボードに文字列を送る方法の備忘録です。

    VBAでは"MSForms.DataObject"からクリップボードの操作を行うことができますが、VBScriptでは取得できないため他の方法が必要です。

    私が思いついた方法としては
    1. "clip.exe"を使用する(クリップボードに送るのみ)
    2. PowerShellにコマンドを送信する
    がありますが、今回は1.の「"clip.exe"を使用する」方法について書いていきます。

    私が思いついた方法としては


    1. clip.exe”を使用する(クリップボードに送るのみ)


    2. PowerShellにコマンドを送信する


    がありますが、今回は1.の「“clip.exe”を使用する」方法をについて


    "clip.exe"とは何か

    "clip.exe"とは、Windowsに最初から入っているプログラムの一つで、種類としてはコンソール アプリケーションというものです(古いWindowsでは入ってないこともあります)。
    これを使うことでクリップボードに文字列を送ることができます。

    コンソール アプリケーションとは何か、ということですが
    ざっくり言うと、起動したときに黒画面(コンソール)が現れるプログラムです。
    例:コマンドプロンプト
    (コマンド ライン ツールと呼ばれることもあります。)


    それではまず、"clip.exe"のヘルプを確認します。
    コマンドプロンプトを起動して「clip /?」と入力すると以下のように表示されます。
    C:\WINDOWS\system32>clip /?


    CLIP

    説明:
    コマンド ライン ツールの出力を Windows クリップボードにリダイレクトします。
    その出力されたテキストをほかのプログラムに貼り付けることができます。

    パラメーター一覧:
    /? このヘルプを表示します。

    例:
    DIR | CLIP 現在のディレクトリ一覧のコピーを Windows クリップボード
    に貼り付けます。

    CLIP < README.TXT readme.txt ファイルのテキストのコピーを Windows
    クリップボードに貼り付けます。

    C:\WINDOWS\system32>clip.exe /?



    CLIP



    説明:


    コマンドライン ツールの出力を Windows クリップボードにリダイレクトします。


    その出力されたテキストをほかのプログラムに貼り付けることができます。



    パラメーター一覧:


    /? このヘルプを表示します。



    :


    DIR | CLIP 現在のディレクトリ一覧のコピーを Windows クリップボード


    に貼り付けます。



    CLIP < README.TXT readme.txt ファイルのテキストのコピーを Windows


    クリップボードに貼り付けます。



    このヘルプの例を元に、VBScriptで記述すると以下のようになります。
    Call CreateObject("Wscript.Shell").Run("%COMSPEC% /c echo " & "コピーしたい文字列" & "|clip",0)
    テキストファイルにコピペして拡張子を"vbs"に変更して実行すれば"コピーしたい文字列"がコピーされます。

    しかし、この記述には問題があり、ごく単純な文字列ならば上の例でもなんとかなりますが、改行や一部の文字が入るとうまく動作しなくなってしまいます。


    それではその問題を解決する方法を考えていきます。

    標準入力を使う


    ヘルプに二つ使用例("DIR|CLIP"と"CLIP<README.TXT")がありましたが、コンソールアプリケーションについての知識があれば、二つの使用例は同じ事を表していることがわかります。

    まず、概念の説明からしていきます
    コンソールアプリケーションには標準入力・標準出力(・標準エラー出力)という概念があります。
    それぞれプログラム外部から入力、または外部に出力するときに使われるものとなります。
    コマンドプロンプトを例にすると
    標準入力はキーボード
    標準出力(・標準エラー出力)はコンソール(黒画面)
    となっています。

    そのためコマンドプロンプトでは、キーボードからコマンドを入力できますし、その結果を画面上で確認することができます。

    この入力先・出力先は以下のような記述をすることで変更することができます。
    1. 「|」(パイプ)
      パイプは、右側の標準入力に、左側の標準出力を送る、といった動作を行います
      例:DIR|CLIP
      "CLIP"の標準入力に、"DIR"コマンドの結果(標準出力)を送る

    2. 「<」入力リダイレクト
      入力リダイレクトは、左側の標準入力に、右側のファイルの中身をテキスト化して送る、といった動作を行います。
      例:CLIP<README.TXT
      "CLIP"の標準入力に、"README.TXT"の中身を送る
    つまりヘルプの例は、"clip.exe"の標準入力にコピーしたい文字列を送れば、その文字列が“clip.exe”によってクリップボードに送られるということを表しています。

    そしてVBScriptでは“Wscript.Shell”の“Exec”メソッドからコンソールアプリケーションの標準入力に直接アクセスすることができます。

    その場合の記述が以下のようになります
    With CreateObject(“Wscript.Shell”)
    With .Exec(“clip”)
    Call .StdIn.Write(“コピーしたい文字列”)
    End With
    End With
    このように記述することで、改行などを含んだ文字列でも"clip.exe"に送ることができます

    なお、VBA・VBScript共通の問題ですが、一部の文字は文字化けしてしまいます。
    その場合はPowerShellなどのUnicodeを扱えるソフト・言語のみでの対応が必要となります。

    サンプル

    ドラッグ&ドロップしたファイルのパスをクリップボードに送るVBScriptです。
    テキストファイルにコピペして、拡張子を"vbs"にすれば使用可能です。
    '引数を、引数毎に改行してクリップボードに送るVBScript
    Option Explicit
    Const MSG_TITLE = "クリップボードにコピー"
    Const CLIP = "%windir%\System32\clip.exe"

    '異常処理:引数なし
    Dim argsCnt 'As Integer
    argsCnt = Wscript.Arguments.Count - 1
    If argsCnt = -1 Then
    Call MsgBox("ファイルをドロップしてください", vbExclamation, MSG_TITLE)
    Call Wscript.Quit
    End If


    'Join用に引数を配列化
    Dim argsArray() 'As String
    ReDim argsArray(argsCnt)

    Dim i 'As Integer
    With Wscript.Arguments
    For i = 0 To argsCnt
    argsArray(i) = .Item(i)
    Next 'i
    End With 'Wscript.Arguments


    'クリップボードに送る(コピーする)文字列作成
    Dim cpText 'As String
    Dim myDel 'As String
    myDel = vbCrLf
    cpText = Join(argsArray, myDel)

    With CreateObject("Wscript.Shell")
    With .Exec(CLIP)
    Call .StdIn.Write(cpText)
    End With '.Exec(CLIP)
    i = 3 '再利用
    Call .Popup("コピーが完了しました" & vbCrLf & "このウィンドウは" & i & "秒後に閉じます", i, MSG_TITLE, vbInformation)
    End With 'CreateObject("Wscript.Shell")

  • マクロからPowerPointでフォントを「本文の~」に戻す

    2016-09-02 21:20
    PowerPointの図形のフォントを「本文のフォント」や「見出しのフォント」にする方法の備忘録です。

    結論

    With [PowerPoint.Shape].TextFrame.TextRange.Font
      .NameAscii = "+mn-lt"
      .NameFarEast = "+mn-ea"
    End With
    斜体部は表記されている型の任意のオブジェクトを示します。

    解説

    変更したいテキスト(TextRangeオブジェクト)のフォント(Fontオブジェクト)に対して
    使いたいフォント名を設定することでフォントを変更することができます。

    Fontオブジェクトの場合は
     英数字用のフォントに影響するのが"NameAscii"プロパティ
     日本語用のフォントに影響するのが"NameFaeEast"プロパティ
    です。

    特定のフォントにしたい場合はフォント名を直接設定しますが
    +本文のフォント」「+本文のフォント - 日本語」のようにテーマなどに依存させたい場合は上記の文字列を設定することで可能となります。

    以下は結果からの推測となりますが
    先頭の"+mn"はマイナーの略で本文。
    後ろの"-lt"、”-ea”はラテン語、東アジア語で英数字と漢字類を表していると思われます。

    なお「+見出しのフォント~」にしたい場合は先頭の"+mn~"を"+mj~"にします。
    "+mj"はメジャーの略で見出しを表しているようです。

    サンプル

    最後に簡単なサンプルを用意しました。
    PowerPoint上で選択している形状のフォントを、英数字・日本語ともに本文のフォントにするマクロとなります。
    単体のテキストボックスなどなら問題なく動作するはずです。

    PowerPointの標準モジュールに貼り付けて"選択している形状のフォントを本文のフォントにする"プロシージャを起動してください。

    こちらからもダウンロードできます
    https://1drv.ms/u/s!AnwcLuebK5DRgYomCI2IPxsikyd_8g

    Sub 選択している形状のフォントを本文のフォントにする()
    If PowerPoint.ActiveWindow.Selection.Type = ppSelectionShapes Then
     Dim tmpShp As PowerPoint.Shape 'スライド上の形状
     For Each tmpShp In PowerPoint.ActiveWindow.Selection.ShapeRange
      Select Case tmpShp.Type
       Case msoTable, msoGroup '要別処理
       Case Else
        If tmpShp.TextFrame.HasText Then
         Call 本文フォントにする(tmpShp)
        End If
      End Select
     Next tmpShp
    End If
    End Sub

    Private Sub 本文フォントにする(iShp As PowerPoint.Shape)
     With iShp.TextFrame.TextRange.Font
      .NameAscii = "+mn-lt"
      .NameFarEast = "+mn-ea"
     End With 'iShp.TextFrame.TextRange.Font
    End Sub

    今回はTextRangeオブジェクトで例を示しましたが、TextRange2オブジェクトのFont2オブジェクトでも同様のことが出来ます。