本ページは公開が終了した情報の複製であり、掲載時点での情報です。本ページに記載されている内容について各所に問い合わせることはご遠慮下さい。
サポート技術情報

[XL]DLL へ引数を渡す方法

文書番号: 402464

最終更新日: 1997/10/23


この資料は以下の製品について記述したものです。


この記事は、以前は次の ID で公開されていました: JP402464

概要

本文書では、Microsoft(R) Visual Basic(R) Proguramming System Applications
Edition (以下 VBA) から、C 言語などで作成した Dynamic Link Libraries (以下 DLL) 内でエクスポートされている関数または API (以下 DLL プロシージャ、便宜上のもので 正しい名称ではありません) を呼び出し、引数を渡す方法をサンプル モジュールと共に 解説しています。

詳細

Declare 宣言方法

  ---------------------------------------------------------------------------
  Declare Sub name Lib "library name" (argument list)
  Declare Function name Lib "library name" (argument list) As return type
  ---------------------------------------------------------------------------

プロシージャ名の置き換え (Alias)

DLL プロシージャの中には、VBA で識別できない名前 (ハイフン "-" など) や予約語と 同じ名前を持つ場合があります。これらの場合には Alias キーワードを使用して VBA で 識別できる名前に置き換える必要があります。
  ---------------------------------------------------------------------------
  Declare Sub name Lib "library name" Alias "Bad name" (argument list)
  Declare Function name Lib "library name" Alias "Bad name" (argument _
      list) As return type
  ---------------------------------------------------------------------------

「値渡し」と「参照渡し」

VBA の引数は「参照渡し (アドレス渡し) 」になっています。「値渡し」で行うには ByVal キーワードを指定する必要があります。

型宣言の対応

Microsoft(R) Windows(R) Software Development Kit (以下 Windows SDK) で用いられて いる各型宣言や C 言語の型宣言と VBA における型宣言は以下のような対応になります。これを参考にして型宣言を書き換えてください。
  整数へのポインタ (LPINT)
    variable name As Integer
  長整数へのポインタ (LPDWORD)
    variable name As Long
  整数 (INT、WORD、BOOL etc.)、ハンドル (hWnd、hDC etc.)
    ByVal variable name As Integer
  長整数 (DWORD、LONG)
    ByVal variable name As Long
  void へのポインタ (void *)
    variable name As Any

文字列型

C 言語で扱う文字列は ASCIIZ 文字列 (Null 文字で終了している文字列) です。引数と して ASCIIZ 文字列を渡すときは ByVal キーワードを使用する必要があります。
  ByVal variable name As String
文字列は常に「参照渡し」になります。ByVal キーワードは「値渡し」という意味では なく、ASCIIZ 文字列 (C 言語などで使用される 0 で終了する文字列) に変換して
渡すという意味なので注意が必要です。また、引数で示した文字列変数に文字列を返す DLL プロシージャの場合、渡した文字列よりも長い文字列を DLL プロシージャが返した 場合には、他の領域を破壊しますので注意が必要です。

ユーザ定義型

「参照渡し」であれば、ユーザ定義型全体を一つの引数として引き渡すことが可能です。ただし、「値渡し」で引き渡すことはできませんので注意が必要です。

配列

数値配列の場合は「参照渡し」であれば、配列全体を一つの引数として引き渡すことが 可能です。ただし、「値渡し」で引き渡すことや文字列配列全体を一つの引数として 引き渡すことはできませんので注意が必要です。
  Declare Sub name Lib "library name" (variable name As Any)
  ...
  name(array name(0))
また、Huge 配列 (64 KB よりも大きな配列) の場合は最初の 64 KB だけにしかアクセス することができませんので注意が必要です。

Null ポインタ

Null ポインタを渡す必要があるときは、その引数を As Any として宣言し、ByVal 0& を 渡します。なお、長さが 0 の文字列を渡した場合は、Null 文字列へのポインタが
渡されます。Null ポインタとしては渡されませんので注意が必要です。
  Declare Sub name Lib "library name" (variable name As Any)
  ...
  name(ByVal 0&)

プロパティ

プロパティは「値渡し」で行う必要があるため、引数が ByVal で宣言されている場合 のみプロパティを直接渡すことができます。なお、文字列プロパティは「参照渡し」に なるため、中間変数を併用する必要があります。また、数値プロパティを「参照渡し」で 行う場合も同様です。

その他の注意点

C 言語で作成されたルーチンは Pascal 呼び出しでなければなりません。
関数ポインタ、符号なし整数型、共用体 (Union)、通貨型、バリアント型、オブジェクト 変数を引き渡すことはできません。

VBA で発生する主なエラー

35 Sub, Function が定義されていません

Sub プロシージャ、または Function プロシージャが定義されていません。指定した DLL などに含まれているかどうか確認してください。

48 DLL 読み込み時のエラーです

指定された DLL を読み込むことができません。指定した DLL を再確認してください。 より詳しい情報は Windows API の LoadLibrary を使用することで得ることができます。

49 DLL が正しく呼び出せません

DLL の呼び出し、または引数の数や型が一致していません。Declare 宣言を再確認して ください。なお、値渡しの場合は ByVal キーワードを付加する必要があります。

サンプル プログラム

左側のエディット ボックスに数値を入力してコマンド ボタンをクリックします。
結果が右側のエディット ボックスに表示されます。
[GRAPHIC: ]
ここでは DLL を作成するための処理系として Microsoft(R) Visual C++(TM) for
Windows(R) Version 1.0 を使用しています。他の処理系の場合は、修正が必要な場合も あります。

サンプル モジュール

  -----------------------------------------------------------------------------
  Option Explicit
  Declare Function noparams Lib "PASSV.DLL" () As Integer
  Declare Function passint Lib "PASSV.DLL" (ByVal a As Integer) As Integer
  Declare Function passlong Lib "PASSV.DLL" (ByVal a As Long) As Long
  Declare Function passfloat Lib "PASSV.DLL" (ByVal a As Single) As Single
  Declare Function passdouble Lib "PASSV.DLL" (ByVal a As Double) As Double
  Declare Sub passpnt Lib "PASSV.DLL" (a As Integer, b As Long, c As Single, _
                                       d As Double)
  Declare Sub passstr Lib "PASSV.DLL" (ByVal a As String)
  Declare Sub passary Lib "PASSV.DLL" (a As Integer, ByVal b As Integer)
  Declare Sub passstrct Lib "PASSV.DLL" (a As teststruct)
  'Declare Sub passstrct Lib "passv.dll" (a As Any)  ' As Any でも可
  Type teststruct
      id As Integer
      ld As Long
      fd As Single
      dd As Double
      sd As String * 6
  End Type
  'ダイアログ表示プログラム
  Sub showDlg()
      Dim icnt As Integer
      For icnt = 0 To 4
        DialogSheets("Dialog1").EditBoxes("edi" & icnt).Text = ""
    Next
    DialogSheets("Dialog1").Show
  End Sub
  'ボタン btn0 ~ btn7 までがクリックされた時の処理
  Sub cmdCallFunc_Click(Index As Integer)
      Dim idt As Integer
      Dim ldt As Long
      Dim sdt As Single
      Dim ddt As Double
      Dim icnt As Integer
      Dim cst As String
      ReDim iary(1 To 4) As Integer
      Dim tstruct As teststruct
      Dim dlg As DialogSheet
      Set dlg = DialogSheets("Dialog1")
      For idt = 1 To 4
          dlg.EditBoxes("edi" & idt).Text = ""
      Next idt
      If Index <> 5 And Val(dlg.EditBoxes("edi0").Text) = 0 Then
        MsgBox ("数値を入力してください")
        'txtValue(0).SetFocus
        dlg.Focus = dlg.EditBoxes("edi0").Name
        Exit Sub
    End If
    Select Case Index
        Case 0:  ' int 型の値を引数で渡す、結果は戻り値
            dlg.EditBoxes("edi" & "1").Text = _
                passint(CInt(dlg.EditBoxes("edi0").Text))
        Case 1:  ' long 型の値を引数で渡す、結果は戻り値
            dlg.EditBoxes("edi" & "2").Text = _
                passlong(CLng(dlg.EditBoxes("edi0").Text))
        Case 2:  ' single 型の値を引数で渡す、結果は戻り値
            dlg.EditBoxes("edi" & "3").Text = _
                passfloat(CSng(dlg.EditBoxes("edi0").Text))
        Case 3:  ' double 型の値を引数で渡す、結果は戻り値
            dlg.EditBoxes("edi" & "4").Text = _
                passdouble(CDbl(dlg.EditBoxes("edi0").Text))
        Case 4: ' int/long/single/double 型のアドレスを引数で渡す結果は引数自身
            idt = CInt(dlg.EditBoxes("edi0").Text)
            ldt = CLng(dlg.EditBoxes("edi0").Text)
            sdt = CSng(dlg.EditBoxes("edi0").Text)
            ddt = CDbl(dlg.EditBoxes("edi0").Text)
            passpnt idt, ldt, sdt, ddt
            dlg.EditBoxes("edi1").Text = idt
            dlg.EditBoxes("edi2").Text = ldt
            dlg.EditBoxes("edi3").Text = sdt
            dlg.EditBoxes("edi4").Text = ddt
        Case 5:  ' string 型の文字列記述子を引数で渡す、結果は引数自身
            cst = dlg.EditBoxes("edi0").Text
            If Len(cst) < 2 Then cst = cst + "  "
            passstr cst
            dlg.EditBoxes("edi1").Text = cst
        Case 6:  ' int 型の配列および要素数を引数で渡す、結果は引数自身
            passary iary(1), 4
            For icnt = 1 To 4
                dlg.EditBoxes("edi" & icnt).Text = iary(icnt)
            Next icnt
        Case 7:  ' 構造体を引数で渡す、結果は引数自身
            tstruct.id = CInt(dlg.EditBoxes("edi0").Text)
            tstruct.ld = CLng(dlg.EditBoxes("edi0").Text)
            tstruct.fd = CSng(dlg.EditBoxes("edi0").Text)
            tstruct.dd = CDbl(dlg.EditBoxes("edi0").Text)
            tstruct.sd = dlg.EditBoxes("edi0").Text
            passstrct tstruct
            dlg.EditBoxes("edi1").Text = tstruct.id
            dlg.EditBoxes("edi2").Text = tstruct.ld
            dlg.EditBoxes("edi3").Text = tstruct.fd
            dlg.EditBoxes("edi4").Text = tstruct.dd
            dlg.EditBoxes("edi0").Text = tstruct.sd
        End Select
  End Sub
  'ボタン btn0 ~ btn7 にそれぞれ登録するプログラム
  Sub btn0_Click()
      cmdCallFunc_Click (0)
  End Sub
  Sub btn1_Click()
    cmdCallFunc_Click (1)
  End Sub
  Sub btn2_Click()
      cmdCallFunc_Click (2)
  End Sub
  Sub btn3_Click()
      cmdCallFunc_Click (3)
  End Sub
  Sub btn4_Click()
      cmdCallFunc_Click (4)
  End Sub
  Sub btn5_Click()
      cmdCallFunc_Click (5)
  End Sub
  Sub btn6_Click()
      cmdCallFunc_Click (6)
  End Sub
  Sub btn7_Click()
      cmdCallFunc_Click (7)
  End Sub
  'ダイアログが表示される時の初期設定 (フォーカスの設定)
  'フォーム 1 に登録するプログラム
  Sub フォーム 1_Show()
      DialogSheets("Dialog1").Focus = _
          DialogSheets("Dialog1").EditBoxes("edi0").Name
  End Sub
  -----------------------------------------------------------------------------
  • DLL ソース ファイル (PASSV.C)
      -----------------------------------------------------------------------------
      #define STRICT
      #include <windows.h>
      #include <string.h>
      /* 関数型: int, 引数: int, 戻り値: 引数の 2 倍 */
      int far _pascal _export passint(int a)
      {
          return a * 2;
      }
      /* 関数型: long, 引数: long, 戻り値: 引数の 2 倍 */
      long far _pascal _export passlong(long a)
      {
          return a * 2;
      }
      /* 関数型: float, 引数: float, 戻り値: 引数の 2 倍 */
      float far _pascal _export passfloat(float a)
      {
          return a * (float)2.0;
      }
      /* 関数型: double, 引数: double, 戻り値: 引数の 2 倍 */
      double far _pascal _export passdouble(double a)
      {
          return a* (double)2.0;
      }
      /* 関数型: void, 引数: int, long, float, double のポインタ */
      /* 結果: 引数の値を 2 倍にして返す */
      void far _pascal _export passpnt(int _far *a, long _far *b, float _far *c,
                                       double _far *d)
      {
          *a = *a * 2;
          *b = *b * 2;
          *c = *c * (float)2.0;
          *d = *d * (double) 2.0;
          return;
      }
      /* 関数型: void, 引数: int の配列 */
      void far _pascal _export passary(int _far a[], int idx)
      {
          int i;
          for (i=0;i<idx;++i){
              a[i] = i;
          }
          return;
      }
      /* 関数型: void, 引数: 構造体, 結果: 各要素の値を 2 倍にして返す */
      typedef struct TESTSTRUCT{
          int         id;
          long        ld;
          float       fd;
          double      dd;
          char        sd[6];
      }FAR * LPSTRUCT;
      void far _pascal _export passstrct(LPSTRUCT lps)
      {
          lps->id = lps->id * 2;
          lps->ld = lps->ld * 2;
          lps->fd = lps->fd * (float)2;
          lps->dd = lps->dd * (double)2;
              _fstrncpy(lps->sd,"change",6);
          return;
      }
      /* 関数型: void, 引数: char のポインタ, 結果: 文字列の先頭 2 バイトを */
      /* ** にして返す */
      /* void far _pascal _export passstr(LPSTR a) */
      void far _pascal _export passstr(char _far *a)
      {
          _fstrncpy (a, "**",2);
          return;
      }
      -----------------------------------------------------------------------------
    
  • DLL 用モジュール定義ファイル (PASSV.DEF)
      -----------------------------------------------------------------------------
      LIBRARY PASSV
      EXETYPE WINDOWS
      DATA    PRELOAD MOVABLE SINGLE
      CODE    PRELOAD MOVABLE DISCARDABLE
      -----------------------------------------------------------------------------
    
  • LoadLibrary による "DLL 読み込み時のエラーです" の解析 "DLL 読み込み時のエラーです" というエラーが発生した場合、Windows API の LoadLibrary を使用することで、発生したエラーの詳細を得ることが可能です。 エラー コードの意味に関しましては Windows SDK のマニュアルを参照して ください。
      -----------------------------------------------------------------------------
      Declare Function LoadLibrary Lib "Kernel" (ByVal f$) As Integer
      Declare Sub FreeLibrary Lib "Kernel" (ByVal h As Integer)
      Dim hInst As Integer
      hInst = LoadLibrary(library name)
      If hInst > 32 Then
          MsgBox "LoadLibrary success"
          FreeLibrary (hInst)
      Else
          MsgBox "LoadLibrary error: " & Format$(hInst)
      End If
      -----------------------------------------------------------------------------
    

注意

このサンプルプロシージャはプログラミング言語の使用方法の一例として紹介するもので あり、内容およびその運用結果に関しては一切の責任を負いません。また、お客様固有の 目的に合わせたプロシージャの内容変更は行っておりませんので、あらかじめご了承 ください。

追加

Microsoft(R) Excel デベロッパーズ キット

Microsoft Excel デベロッパーズ キットは、主に Excel 5.0 を使用して
アプリケーションおよび Excel 5.0 用のアドイン プログラムを開発するソフトウェア 開発者の方々を対象に、必要な情報を提供します。C を既に理解されていて、Excel 5.0 および Microsoft(R) Visual Basic(R) Programming System Applications Edition
(以下 VBA) または Excel 4.0 マクロを熟知されていることが前提となっています。 本書の内容に関するご質問は、株式会社アスキー 第一テクライト編集部まで、かならず 封書 (返信用切手同封のこと) にてお願いいたします。なお、本書の範囲を越える質問に 関しては、お答えできません。

Keywords: KBHOWTO KB402464
Technology: kbExcel500 kbExcelSearch kbExcelWinSearch

inserted by FC2 system