Top / TIPS / いまさらながらタイプライブラリ

タイプライブラリを使用して、API を呼ぶことができます。


タイプライブラリの作成

ODL ファイルを作成する

SampleTLB.odl

   [
       uuid(4a91746e-a044-4baa-a42d-c3a8d4003825),         //  GUIDGEN, UUIDGEN 等で生成
       helpstring("GetWindowText Sample"),                 // 「参照設定」ダイアログで表示される名称
       version(1.0)                                        //  バージョン
   ]
   library SampleTLB
   {
       //
       //  宣言をカッコよく(^_^;)
       //
       typedef long    HWND;
       typedef long    DWORD;
       //
       // エラー値取得用
       //
       [dllname("kernel32")]
       module kernel32 {
           [entry("GetLastError")]
           long GetLastError(void);
       }
       //
       // GetWindowTextA と GetWindowTextW
       //
       [dllname("user32")]
       module user32 {
           [entry("GetWindowTextA")]
           long GetWindowTextA(
               [in]    HWND    hwnd,
               [in]    LPSTR   lpString,
               [in]    DWORD   cch
           );
           [entry("GetWindowTextW")]
           long GetWindowTextW(
               [in]    HWND    hwnd,
               [in]    BSTR    lpString,
               [in]    DWORD   cch
           );
       }
   }

コンパイル

上のコードを sampleTLB.odl として保存し、mktyplib でコンパイルします。
コマンドプロンプトから実行します。

   E:\TEST\TLB>mktyplib  sampleTLB.odl
   Microsoft (R) Type Library Generator  Version 2.20.4230
   Copyright (c) Microsoft Corp. 1993-1995.  All rights reserved.
   
   Successfully generated type library 'sampleTLB.tlb'.
   
   E:\TEST\TLB>

使い方

できあがった 'sampleTLB.tlb' を、VB から参照設定すると、以下のように API を使えます。

   Private Sub Form_Load()
       Dim Buffer As String
       Dim hwndDest As Long
   
       hwndDest = Me.hWnd
       Buffer = Space(1024)
   
       If GetWindowTextA(hwndDest, Buffer, Len(Buffer)) Then
           Text1.Text = Left(Buffer, InStr(Buffer, vbNullChar) - 1)
       Else
           Debug.Print GetLastError
       End If
   
       If GetWindowTextW(hwndDest, Buffer, Len(Buffer)) Then
           Text2.Text = Left(Buffer, InStr(Buffer, vbNullChar) - 1)
       Else
           Debug.Print GetLastError
       End If
   
   End Sub

解説

おおまかな構造は以下のようになります。

  [
      ヘッダ
  ]
  library ライブラリ名
  {
      // 型宣言
      typedef
      typedef enum
      typedef struct

      // モジュール宣言
      [dllname("DLL名")]
      module モジュール名 {
          const 
          関数
      }
  }

ヘッダ

   [
       uuid(4a91746e-a044-4baa-a42d-c3a8d4003825),         //  GUIDGEN, UUIDGEN 等で生成
       helpstring("GetWindowText Sample"),                 // 「参照設定」ダイアログで表示される名称
       version(1.0)                                        //  バージョン
   ]

uuid

注釈のとおり、GUIDGEN, UUIDGEN で生成された文字列をセットしてください。

helpstring

「参照設定」ダイアログで表示される名称になります。

version

特に指定する必要はありません。

ライブラリ名

   library SampleTLB
   {
       ・
       ・
       ・
   }

ライブラリの名前を宣言します。

型宣言

       typedef long    HWND;
       typedef long    DWORD;

エイリアスを宣言します。
C ヘッダファイルの記述に合わせると、なんとなくカッコ良いので宣言してます。(^_^;)
CL.EXE のプリプロセッサを使っているので、#include 等も使用できます。
WINDEF.H にある型を宣言したファイルを作成しておくと良いかも。
符号なしの整数は VB で扱えませんので注意してください。

列挙型

   typedef enum _SID_NAME_USE {
     SidTypeUser             = 1,
     SidTypeGroup,
     SidTypeDomain,
     SidTypeAlias,
     SidTypeWellKnownGroup,
     SidTypeDeletedAccount,
     SidTypeInvalid,
     SidTypeUnknown,
     SidTypeComputer,
     SidTypeLabel
   } SID_NAME_USE;
   typedef SID_NAME_USE *PSID_NAME_USE;

C のように、複数のエイリアスを指定できません。

構造体

   typedef struct tagRECT {
      LONG left;
      LONG top;
      LONG right;
      LONG bottom;
   } RECT;
   typedef RECT    *LPRECT;

VB のオブジェクトブラウザで見ると、メンバ名でソートされてしまうのが難点。

モジュール宣言

       [dllname("kernel32")]
       module kernel32 {
           ・
           ・
           ・
       }

使用する DLL 名とモジュール名を宣言します。

定数

            const long ANYSIZE_ARRAY = 1;
            const LPSTR SE_CREATE_TOKEN_NAME = "SeCreateTokenPrivilege";

演算が使えないのがにんともかんとも。

関数

           [entry("GetWindowTextA")]
           long GetWindowText(
               [in]    HWND    hwnd,
               [in]    LPSTR   lpString,
               [in]    DWORD   cch
           );

entry に、DLL のエクスポートされた関数名を指定し、構文を記述します。
上の例では、GetWindowText を VB から使用します。
引数の型に列挙型を指定すると、インテリセンスが有効になります。

VB の型との比較表は以下になります。

VBODL
Booleanboolean
Byteunsigned char
Integershort
Longlong
Singlefloat
Doubledouble
CurrencyCURRENCY
StringBSTR/LPSTR
VariantVARIANT
DateDATE
ObjectIDispatch*
Anyvoid*

注意!

ANSI バージョンを使うとエラー値が取れない

Declare で宣言した API を呼び出したとき、エラー値は Err.LastDllError で取得できますが、タイプライブラリ経由で呼び出したものは GetLastError API を呼び出して取得する必要があります。

VB のコーディングで

       hwndDest = Me.hWnd

となっている箇所をコメントにしてみてください。
GetWindowText の戻り値はゼロになるので、GetLastError の戻り値がイミディエイトウインドウに出力されます。

結果は

    0
    1400

になると思います。
ANSI バージョンを使うと、API コール後、ANSI → Unicode の変換が走るので、エラー値がクリアされてしまうのです。
もちろん、long で宣言しておいて、アドレスを渡せば、その限りではありません。

VB.NET に移行できない(;_;)

残念ながら VB.NET では使用できませんでした。

WIN32API.tlb

API ビューワに附属している WIN32API.txt をタイプライブラリにしてみました。

・構造体の名前は、先頭に typ を付加しています。
・Unicode バージョンがあると予想されるもの(末尾がAのもの)については、関数名+W も宣言してあります。
・構造体/String/Any を引数に含むものは、ポインタで呼び出せるよう 関数名 + AsPtr でも宣言しています。

GetWindowText なら

関数名第二引数の型コード
GetWindowTextLPSTRANSI
GetWindowTextAsPtrlongANSI
GetWindowTextWBSTRUnicode
GetWindowTextAsPtrWlongUnicode

と4つのパターンが存在します。

機械的に変換しただけなので、間違いがあったらごめんなさい(_ _;)




トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   最終更新のRSS
Last-modified: 2012-06-28 (木) 16:41:43 (1824d)