Share via


巨人の肩の上に立つ

David Shank
Microsoft Corporation

2000 年 7 月 6 日

今月のコラムのタイトルはアイザック ニュートン卿の言葉を引用したものです。ニュートンは彼自身の偉業について意見を求められたときに、すぐさま心からの謙遜の意を込めてこう答えました。「もし私が他の人よりも遠くを見ているとしたら、それは巨人の肩の上に立っているからだ」

この言葉は非常に興味深いものですが、それと Office を使ったカスタム ソリューションの作成と何の関係があるのか疑問に思われるでしょう。関係は大ありです。ニュートンが言いたかったことは、自分の偉業がどんなに華々しいものであろうと、それは先哲の偉業の上に成り立っているのだということです。開発者は他人が作ったものを「流用する」という悪名を背負っていますが、そのことは決して間違ったことではなく、実際非常に大きな意義があるのです。MSDN 自体が掲げている基本的な原則の 1 つに、他人が記述した情報やサンプル コードを提供してそれを利用してもらう、ということがあります。MSDN のスタッフは、コードの書き方を覚えるには、その書き方を読むだけという方法より、いくつかのよいサンプル コードを提供して実際に見てもらうよいと考えています。

他人が記述したコードを使って Office のプログラミングについて詳しく学習するだけにとどまらず、コードそのものを自分のカスタム ソリューションの中で利用できれば理想的です。問題は、有益なコード サンプルを収集、蓄積するために何らかの組織立てた方法を考えるということです。別の見方をすれば、後で再利用できるように自分自身のコードを蓄積する手段を考えるということでもあります。開発者は、コードの収集と保存、そして再利用のためにコードを蓄積する方法について、さまざまな手段を持っています。たとえば、高度なコード管理アプリケーションを購入するといった方法から、お気に入りのルーチンをテキスト ファイルにコピーしてディスクに保存するといった方法まであります。

繰り返し必要になることがわかっているようなプロシージャやコードなどを蓄積しておける、検索が可能な 1 個のコード レポジトリ(貯蔵庫)を用意しておけば、いかに便利か想像してみてください。さらに、そのレポジトリに、すぐに使えるプロシージャが無数に蓄積されていたとしたらどんなに便利なことでしょう。

市販されている良質なコード ライブラリを購入したり、あるいは自分でコード ライブラリを作成するという方法もありますが、Microsoft Office Developer(https://www.microsoft.com/office/developer/)をお持ちの方は既に良質なコード ライブラリが手元にありますから、これを活用しない手はありません。このコード ライブラリには多数のサンプル コードが付属しており、自分のカスタム ソリューションの中で利用できます。

今月のコラムでは、Microsoft Office Developer(MOD)で利用できるコード ライブラリアン アドインについて解説します。今回は実際のコード ライブラリアンからいくつかのコード サンプルを抜粋して紹介しており、MOD を持っていない方にも有益な内容だと思います。これらのコード サンプルはコピーしてそのまま自分のカスタム ソリューションの中で利用できます。

コード ライブラリアンとは

MOD に付属の COM アドインであるコード ライブラリアンは、コード モジュールや関数、コードなどの蓄積と取得をドラッグ アンド ドロップで行えるデータベースです。MOD コード ライブラリアンには、サンプル コードがあらかじめ登録されており、それらを自分の Office ソリューションの中でそのまま利用できます。また、自分のサンプル コードをデータベースに追加することでコード ライブラリアンをカスタマイズすることもできます。さらに、ほかの Office 開発者製品(https://msdn.microsoft.com/office/default.asp)でもコード ライブラリアンを使ったサンプル コードが配布されており、最新のものでは Microsoft Visio ソリューションを扱ったサンプル コードが収められています。

注意: コード ライブラリアンを使わずにソース データベース内のコードにアクセスすることはできません。

MOD をインストールしたあと、MOD を開くには先にアドインをロードする必要があります。

  1. 任意の Office アプリケーションから Visual Basic Editor(VBE)を開きます。

  2. VBE の[アドイン]メニューから[アドイン マネージャ]コマンドをクリックします。

  3. 利用可能なアドインの一覧から[コード ライブラリアン]を選択します。

  4. ロードする / ロードしない]チェック ボックスをオンにしてから[OK]をクリックし、[アドイン マネージャ]ダイアログ ボックスを閉じます。

  5. VBE の[アドイン]メニューを開き、[コード ライブラリアン]コマンドをクリックします。

コード ライブラリアンでは、Windows エクスプローラに似たインターフェイスの中でサンプル コードが整理されています。左側のペインにはメインのコード カテゴリが表示され、右側のペインには個々の関数、サブルーチン、モジュール、およびクラス モジュールが表示されます。プロシージャの説明は右側のペインの下にあるメッセージ領域に表示されます。

概観図 1:コード ライブラリアン

プロシージャをダブルクリックすると、そのプロシージャが別のウィンドウに表示されます。たとえば、次の画面は LastDayOfMonth プロシージャをダブルクリックした結果です。

概観図 2:プロシージャの表示

コード ライブラリアンではドラッグ アンド ドロップ形式の編集がサポートされています。このため、プロシージャをコード ライブラリアンからドラッグしてプロジェクトにドロップすることで、プロシージャをプロジェクトに追加できます。同様に、自分のプロシージャを強調表示にしてコード ライブラリアンまでドラッグすることで、自分のプロシージャをコード ライブラリアンに追加できます。

MOD コード ライブラリアンは、自分のプロシージャやほかの人からコピーしたプロシージャを手軽に蓄積して分類することのできる便利なツールです。また、コード ライブラリアンの使用するかどうかは別として、再利用しやすいコードを書く習慣を身に付けておくことは、とてもよいことです。詳細については、「再利用可能なコードを作成する」 を参照してください。

サンプル コードのサンプル

ここではコード ライブラリアンの中からわずかなサンプル コードしか紹介することができません。これらは、コード ライブラリアンに含まれている再利用可能なコードの例として示すものであり、再利用可能なプロシージャの書き方を示す例でもあります。どのサンプル コードもこのコラムからコピーしてそのまま自分の Office ソリューションの中で利用できます。

日付と時刻の例

人の年齢の計算:

  Function Age(Bdate, DateToday) As Integer
'
' Returns the Age in years between two dates
' Doesn't handle negative date ranges, i.e. Bdate> DateToday
'
  If Month(DateToday) <Month(Bdate) Or (Month(DateToday) = Month(Bdate) And Day(DateToday) <Day(Bdate)) Then
    Age = Year(DateToday) - Year(Bdate) - 1
  Else
    Age = Year(DateToday) - Year(Bdate)
  End If
End Function

文字列値から日付値への変換:

  Function String2Date(S, Fmt As String)
'
' Converts strings to dates depending on Fmt
' See Help on Format for what the various strings mean
' Comments use 27 May, 1993, as example date to show input text
'
  If VarType(S) <> 8 Then
    String2Date = Null
    Exit Function
  End If
  Select Case Fmt
    Case "MMDDYY", "MMDDYYYY"          '052793   05271993
      String2Date = CVDate(left(S, 2) & "/" & Mid(S, 3, 2) & "/" & Mid(S, 5))
    Case "DDMMYY", "DDMMYYYY"          '270593   27051993
      String2Date = CVDate(Mid(S, 3, 2) & "/" & left(S, 2) & "/" & Mid(S, 5))
    Case "YYMMDD"          '930527
      String2Date = CVDate(Mid(S, 3, 2) & "/" & Right(S, 2) & "/" & left(S, 2))
    Case "YYYYMMDD"          '19930527
      String2Date = CVDate(Mid(S, 5, 2) & "/" & Right(S, 2) & "/" & left(S, 4))
    Case "MM/DD/YY", "MM/DD/YYYY", "M/D/Y", "M/D/YY", "M/D/YYYY", "DD-MMM-YY", "DD-MMM-YYYY"
      String2Date = CVDate(S)
    Case "DD/MM/YY", "DD/MM/YYYY"          '27/05/93   27/05/1993
      String2Date = CVDate(Mid(S, 4, 3) & left(S, 3) & Mid(S, 7))
    Case "YY/MM/DD"          '93/05/27
      String2Date = CVDate(Mid(S, 4, 3) & Right(S, 2) & "/" & left(S, 2))
    Case "YYYY/MM/DD"          '1993/05/27
      String2Date = CVDate(Mid(S, 6, 3) & Right(S, 2) & "/" & left(S, 4))
    Case Else
      String2Date = Null
  End Select
End Function

ある月の特定の日の検索:

  Function FirstOfNextMonth(Optional dteDate As Date) As Date

    If CLng(dteDate) = 0 Then
        dteDate = Date
    End If

    FirstOfNextMonth = DateSerial(Year(dteDate), Month(dteDate) + 1, 1)
End Function

Function LastOfPreviousMonth(Optional dteDate As Date) As Date

    If CLng(dteDate) = 0 Then
        dteDate = Date
    End If

    LastOfPreviousMonth = DateSerial(Year(dteDate), Month(dteDate), 0)

End Function

コマンドバーとメニューの例

コマンドバーの作成:

  Function CBCreateCommandBar(strCBarName As String, _
                            Optional lngBarType As Long = 0) As CommandBar

    ' This procedure creates a command bar of the type
    ' specified in the lngBarType argument. The default
    ' command bar type is a toolbar.

    Dim cbrCmdBar   As CommandBar
    Dim strBarType  As String
    Dim lngPosition As Long

    On Error Resume Next
    Set cbrCmdBar = Application.CommandBars(strCBarName)
    If Err = 0 Then
        ' The command bar already exists.
        If cbrCmdBar.BuiltIn = True Then
            CBCreateCommandBar = False
            Exit Function
        End If

        strBarType = CBGetCBType(cbrCmdBar)

        If MsgBox("'" & strCBarName & "' is an existing " & strBarType _
            & " type command bar. Are you sure you want to delete it?", vbYesNo, _
            "Replace Existing Command Bar?") = vbNo Then
            CBCreateCommandBar = False
            Exit Function
        Else
            cbrCmdBar.Delete
            Set cbrCmdBar = Nothing
        End If
    Else
        ' The command bar does not exist, so reset the error number to zero
        ' and create the new command bar.
        Err = 0
    End If
    If lngBarType <> msoBarMenuBar And lngBarType <> msoBarPopup Then
        lngBarType = msoBarTypeNormal
    End If

    Select Case lngBarType
        Case msoBarTypeNormal
            Set cbrCmdBar = Application.CommandBars.Add(Name:=strCBarName)
        Case msoBarMenuBar
            Set cbrCmdBar = Application.CommandBars.Add(Name:=strCBarName, Position:=msoBarMenuBar) ', , 'True)
        Case msoBarPopup
            Set cbrCmdBar = Application.CommandBars.Add(Name:=strCBarName, Position:=msoBarPopup)
    End Select

    Set CBCreateCommandBar = cbrCmdBar
End Function

コマンドバーのコピー:

  Function CBCopyCommandBar(strOrigCBName As String, _
                          strNewCBName As String, _
                          Optional blnShowBar As Boolean = False) As Boolean

    ' This procedure copies the command bar named in the strOrigCBName
    ' argument to a new command bar specified in the strNewCBName argument.

    Dim cbrOriginal         As CommandBar
    Dim cbrCopy             As CommandBar
    Dim ctlCBarControl      As CommandBarControl
    Dim lngBarType          As Long

    On Error GoTo CBCopy_Err

    Set cbrOriginal = CommandBars(strOrigCBName)

    lngBarType = cbrOriginal.Type
    Select Case lngBarType
        Case msoBarTypeMenuBar
            Set cbrCopy = CommandBars.Add(Name:=strNewCBName, Position:=msoBarMenuBar)
        Case msoBarTypePopup
            Set cbrCopy = CommandBars.Add(Name:=strNewCBName, Position:=msoBarPopup)
        Case Else
            Set cbrCopy = CommandBars.Add(Name:=strNewCBName)
    End Select

    ' Copy controls to new command bar.
    For Each ctlCBarControl In cbrOriginal.Controls
        ctlCBarControl.Copy cbrCopy
    Next ctlCBarControl

    ' Show new command bar.
    If blnShowBar = True Then
        If cbrCopy.Type = msoBarTypePopup Then
            cbrCopy.ShowPopup
        Else
            cbrCopy.Visible = True
        End If
    End If
    CBCopyCommandBar = True
CBCopy_End:
    Exit Function
CBCopy_Err:
    CBCopyCommandBar = False
    Resume CBCopy_End
End Function

コマンドバーからコントロールを削除:

  Function CBDeleteCBControl(strCBarName As String, _
                           strCtlName As String)

    On Error Resume Next
    Application.CommandBars(strCBarName).Controls(strCtlName).Delete
End Function

コマンドバー コントロールの表示 / 非表示の切り替え:

  Function CBCtlToggleVisible(strCBarName As String, _
                            strCtlCaption As String) As Boolean

    ' Toggle the Visible property of the strCtlCaption control
    ' on the strCBarName command bar.

    Dim ctlCBarControl As CommandBarControl

    On Error Resume Next

    Set ctlCBarControl = Application.CommandBars(strCBarName).Controls(strCtlCaption)
    ctlCBarControl.Visible = Not ctlCBarControl.Visible
    If Err = 0 Then
        CBCtlToggleVisible = True
    Else
        CBCtlToggleVisible = False
    End If
End Function

文字列の操作

文字列の一部の削除:

  Function RemoveString(ByVal strSource As String, _
                      strStart As String, _
                      strEnd As String, _
                      Optional intEndCount As Integer = 0, _
                      Optional blnReturnChunk As Boolean = False) As String

    ' Remove the string from strSource beginning at
    ' the start of strStart and ending at the end of
    ' strEnd.
    ' Return the new string to the calling procedure.
    ' If any of the input parameters are invalid, then return
    ' a zero-length string.

    Dim intStartPos     As Integer
    Dim intEndPos       As Integer
    Dim strStartPiece   As String
    Dim strEndPiece     As String

    intStartPos = InStr(strSource, strStart)

    If intEndCount = 0 Then
        intEndPos = InStr(strSource, strEnd) + Len(strEnd)
    Else
        intEndPos = InStr(strSource, strEnd) + intEndCount
    End If

    If Len(strSource)> 1 And intStartPos> 0 And intEndPos> 1 Then
        If blnReturnChunk = False Then
            strStartPiece = Left(strSource, intStartPos - 1)
            strEndPiece = Mid(strSource, intEndPos)
            RemoveString = Trim(strStartPiece & strEndPiece)
        Else
            RemoveString = Trim(Mid(strSource, intStartPos, (intEndPos - intStartPos)))
        End If
    Else
        RemoveString = ""
    End If
End Function

文字列をディスク上のファイルとして保存:

  Function SaveStringAsTextFile(strSource As String, _
                              strFileName As String) As Boolean

    ' Save the string in strSource to the file supplied
    ' in strFileName. If the operation succeeds, return True;
    ' otherwise, return False. If the file described by
    ' strFileName already exists, append strSource to any
    ' existing text in the file.

    Dim intFileNumber As Integer

    On Error GoTo SaveString_Err

    ' Assume that the operation will succeed.
    SaveStringAsTextFile = True

    If Len(strSource)> 0 And InStr(strFileName, ".txt")> 0 Then
        If InStr(strFileName, ":") = 0 Or InStr(strFileName, "\") = 0 Then
            ' Invalid file path submitted.
            SaveStringAsTextFile = False
        Else
            ' Save file to disk.
            intFileNumber = FreeFile
            Open strFileName For Append As intFileNumber
            Print #intFileNumber, strSource;
            Close intFileNumber
        End If
    Else
        SaveStringAsTextFile = False
    End If

SaveString_End:
    Exit Function
SaveString_Err:
    MsgBox Err.Description, vbCritical & vbOKOnly, _
         "Error Number " & Err.Number & " Occurred"
    Resume SaveString_End
End Function

ファイル パスからファイル名を取得:

  Function NameFromPath(strPath As String) As String
    ' This procedure takes a file path and returns
    ' the file name portion.

    Dim lngPos          As Long
    Dim strPart         As String
    Dim blnIncludesFile As Boolean

    ' Check that this is a file path.
    ' Find the last path separator.
    lngPos = InStrRev(strPath, "\")
    ' Determine whether string after last backslash
    ' contains a period.
    blnIncludesFile = InStrRev(strPath, ".")> lngPos
    strPart = ""

    If lngPos> 0 Then
        If blnIncludesFile Then
            strPart = Right$(strPath, Len(strPath) - lngPos)
        End If
    End If
    NameFromPath = strPart
End Function

文字列中の単語数をカウント:

  Function CountWords(strText As String) As Long
    ' This procedure counts the number of words in a string.

    Dim astrWords() As String

    astrWords = Split(strText)
    ' Count number of elements in array—this will be the
    ' number of words.
    CountWords = UBound(astrWords) - LBound(astrWords) + 1
End Function

参考資料

ここではコード ライブラリアンに含まれているサンプル コードのごく一部を紹介しました。これらはあらゆる Office プロジェクトの中で再利用できるように適切に記述された便利なプロシージャの例です。このほか、コード ライブラリアンでの作業に関しては次の資料を参考にできます。

David Shank は、Office チームにおいて開発者向けのドキュメンテーションを専門とするプログラマーでありライターでもあります。彼はレドモンドの東に位置する山の上で生活していて、ノースウエストには残り少ないネイティブであるという噂です。