Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2017年04月06日] [更新 2018年08月28日] Delphi 一般・その他
Indy コンポーネントのインストール
動作確認等 主に Windows 7 U64(SP1 + Delphi 6(UP2) Pro + Indy 10.6.2
[整理番号 - 0530]







Indy コンポーネントのインストール - Delphi 6 の例


Delphi 6 に Indy 10.6.2 をインストールする手順です。
Delphi 6 の Indy のバージョンはデフォルトで 8 です。Delphi 7 では 9 です。本ページの方法でインストールすれば、2017年04月06日現在の最新のバージョンの Indy を利用できるようになります。
インストールは以下の 2 つの方法があります。
  • Indy が提供しているインストール用のバッチファイルを使用する
  • パッケージファイルを開いて手動でコンパイルする
本ページではパッケージファイルを開いてコンパイルする方法を最初に説明しています。


[備考]
他のバージョンの Delphi へのインストールも、本ページで説明している方法とほとんど同じです。上の DEKO さんのサイトの記事を参考にしてください。

今回インストールした Indy 10.6.2 は Delphi 6 Personal 版にもインストールできます。今回のインストールのテストでは、同一 PC 上の Delphi 6(UP2) Pro, Delphi 2007-R2 Pro, Delphi XE(UP1) Pro および Delphi XE5(UP2) Pro で確認しています。





01_インストール済み Indy コンポーネントと関係ファイルの削除


まず、既にインストールされている Indy のパッケージの削除と関係ファイルを削除します。この作業はバッチファイルを使用してインストールする場合も必要です。
元のバージョンに戻すためのファイルのバックアップ方法については、上の参考リンクの記事で確認してください。以下の説明は、旧バージョンの Indy を削除することを前提にした手順です。

[コンポーネント] [パッケージのインストール] のダイアログで、以下の Indy のパッケージを削除します。もし、他にも Indy の名前のあるパッケージがあれば、それも削除します。


Internet Direct (Indy) for D6 Propert and Component Editor


図1
パッケージの削除
  • Indy 10 をインストールしていると複数ある
  • 関係ファイルの削除も必要

パッケージを削除しただけでは関係ファイルは削除されません。Delphi のインストール先のフォルダ内に下表に示すファイルがあればそれらを削除します。

Delphi はコンパイル時に下表に示すフォルダ内を検索します。したがって、旧いバージョンのファイルが存在すると、それらのファイルが原因で「未定義のエラー」や「異なるバージョンによりコンパイルされています」あるいは「... が見つかりません」等のエラーが発生し、コンパイルやインストールに失敗することがあります。


対象フォルダ フォルダ内の削除すべきファイル 備考
bin dclIndy*.*
Indy*.*
Indy の文字があるファイル全て
lib dclIndy*.*
Id*.*
Indy*.*

Indy の文字があるファイル全て
先頭が Id のファイル全て

lib 階層下のフォルダにあればそれも削除

lib\Indy10 *.* フォルダごと削除
source\Indy
source\Indy10
*.* フォルダごと削除
Projects\Bpl dclIndy*.*
Indy*.*
Indy の文字があるファイル全て


[備考]
先頭が Id のファイルがあるのは lib フォルダ、または lib フォルダの階層下のフォルダです。
Delphi のバージョンによっては、似たような名前があります。例えば InDAY... (d と y の間に a がある) というのがあります。これは削除しないでください。





02_Indy コンポーネントの入手


Indy コンポーネントは以下のリポジトリから SVN を利用して入手できます。ブラウザで閲覧する時はユーザアカウントを Indy-Public-RO にして、パスワードは空白とします。
今回は、Indy 10.6.2 - Berlin RTM をダウンロードしてインストールしました。




図2
Indy のダウンロード
  • 今回は Indy 10.6.2 - Berlin RTM をダウンロードした

[備考]
SVN (Subversion) の機能は最近の Delphi には実装されています。
例えば Delphi 10.1 Berlin Starter では [ファイル] [バージョン管理リポジトリから開く...] で、[Sebversion] を選択すると利用できます。
上の図は TortoiseSVN というソフトですが、少し古いバージョンです。





03_ライブラリパスの設定


ダウンロードしたフォルダの階層下の Lib フォルダ内の、以下の 3 つのフォルダにライブラリのパスを通しておきます。設定は [ツール] [環境オプション] でダイアログを表示して、[ライブラリ] タブで行います。

後述のバッチファイルを使用するインストールの場合、ライブラリパスの設定は必要ありません。



D:\000_Delphi\Indy10_6_2\Lib\Core
D:\000_Delphi\Indy10_6_2\Lib\Protocols
D:\000_Delphi\Indy10_6_2\Lib\System


[備考]
ダウンロードした Indy を [Indy10_6_2] という名前のフォルダに置いていますが、これは説明のために付けています。バージョン番号の付いた名前ですと、バージョンアップした時に困ります。実際には別の名前にしてください。10.6.2 以降という意味であれば構わないでしょう。



図3
ライぶりパスの設定
  • Indy の Lib フォルダ階層下の以下のフォルダにパスを通す
  • Core
    Protocols
    System




04_パッケージを開いてコンパイル


Delphi の IDE を起動して、Lib フォルダ階層下の以下のパッケージファイルを開きます。
開くファイルの順番は関係ありませんが、コンパイルは下表のファイルの順番に実行する必要があります。これは、パッケージでコンパイルするファイルに依存関係があるからです。


Lib 内のフォルダ名 開くパッケージファイル名 (Delphi 6 の場合)
System IndySystem60.dpk
Core IndyCore60.dpk
Protocols IndyProtocols60.dpk
Core dclIndyCore60.dpk
Protocols dclIndyProtocols60.dpk


パッケージファイル名をダブルクリックするか、ファイル名を選択して [アクティブ] ボタンをクリックしてダイアログを前面に表示します。そしてコンパイルします。上の表の順番に 5 つのパッケージを全てコンパイルします。

コンパイルしてもダイアログを閉じないでください。ダイアログを閉じてしまうと、パッケージファイルも閉じてしまいます。



図4
パッケージのコンパイル
  • ファイル名を選択して [アクティブ]
  • [コンパイル] したら Unit1 のウィンドウをクリック
  • [パッケージ] のダイアログは閉じない
  • 太字になっている状態が操作対象のパッケージ名

[備考]
Delphi 2007, XE 等では 1 回の操作でまとめてコンパイルできます。
一番上のパッケージ名をダブルクリックして選択状態にした後、ポップアップメニュー [ここから下を] のサブメニューの [ここから下を全てコンパイル] をクリックします。

いくつかの Delphi のバージョン用に、拡張子が .groupproj のプロジェクトグループが用意されています。これを使用すると便利です。。





05_パッケージのインストール


パッケージを全てコンパイルしたら、先頭が dcl の以下の 2 つのパッケージを、この順番でインストールします。
パッケージファイル名をダブルクリックするか、ファイル名を選択して [アクティブ] ボタンをクリックしてダイアログを前面に表示します。そしてインストールします。



dclIndyCore60.bpl 
dclIndyProtocols60.bpl


図5
パッケージのインストール
  • 以下の順番にインストール
    dclIndyCore60.bpl dclIndyProtocols60.bpl
  • ファイル名を選択したら [アクティブ]
  • [インストール] して Unit1 のウィンドウをクリック
  • 太字になっている状態のパッケージ名が操作対象

これでンストールは終了です。Delphi の IDE を閉じて再度起動します。
[コンポーネント] [パッケージのインストール] のダイアログを表示すると、2 つのパッケージがインストールされていることが確認できます。

コンパイル済みのユニットファイルは、Indy の Lib フォルダ階層下の、該当するパッケージがあるフォルダ内に保存されています。コンパイル済のパッケージファイルは、Delphi のインストール先の Bpl フォルダ内にあります。



図6
登録されたパッケージ

[備考]
以上の方法でインストールした場合、コンパイル済みのパッケージのファイルは Delphi 6 等は上の図のように%ProgramFiles% 階層下のフォルダに保存されます。Windows Vista 以降に対応したバージョンの Delphi では、%PUBLIC%\パブリックのドキュメント の階層下に保存されます。
具体的な場所は、上の図の [コンポーネント] [パッケージのインストール] のダイアログを表示して、パッケージ名を選択すれば確認できます。




06_バッチファイル Fulld_6.bat を使用するインストール


Indy にはインストール用のバッチファイルが用意されています。そのバッチファイルを使用したインストール方法です。ただし、全ての Delphi のバージョンに用意されているわけではないようです。確認が必要です。

バッチファイルを実行する前に、インストール済みの Indy のパッケージを削除し、関係するファイルを削除しておきます。
コマンドプロンプトを管理者権限で起動したら、以下のコマンドを全て選択コピーして、コマンドプロンプトに貼り付けて実行します。

最初のコマンドはカレントディレクトリを Indy の Lib フォルダに移動します。次のコマンドが Indy に用意されているバッチファイル名です。Delphi 6 用は Fulld_6.bat です。
フォルダ名 (ディレトクリ名) 等は各自の環境に合わせて変更します。


cd C:\000_Delphi\Indy10_6_2\Lib
Fulld_6.bat


図7
インストール実行
  • コマンドプロンプトを管理者権限で起動
  • 上のコマンドを貼り付けて実行
図8
インストールしたファイルの場所
  • Indy のフォルダ内に D6 というフォルダが自動で作成される
  • その中に保存される
  • 赤枠の 2 つをパッケージとして登録する

コンパイルされたユニットとパッケージファイルは、Indy のフォルダの階層下に D6 という名前のフォルダが自動で作成され、そこに保存されます。また、この D6 というフォルダにはライブラリのパスが自動で設定されます。

上記の操作でインストールしてもパッケージは登録されません。
[コンポーネント] [パッケージのインストール] のダイアログで登録します。[追加] ボタンでファイルの選択ダイアログを表示したら、上の図の赤枠の、先頭の文字列が dcl の 2 つのパッケージファイルを選択します。下図のようにパッケージが登録されます。



[備考]
ソースコードにライブラリのパスが通ってなくてもコンポーネントは利用できますが、必要であれば上の方の記事を参考にして設定してください。
ソースコードを改変する必要がなければ、ライブラリのパスを設定するのではなく、[ブラウザ検索パス] を追加した方が無難です。[ブラウザ検索パス] は [ライブラリパス] の設定と同じダイアログを表示して設定できます。

ソースコードにライブラリのパスを設定すると、ソースコードがある場所にもコンパイル済みのファイルが保存されてしまいます。これはトラブル発生の原因となります。



図9
パッケージの登録
  • [追加] ボタンで登録する
  • この図は登録済みの状態




07_Indy におけるコードページの設定とデコードとエンコード


コミュニティの場でも文字化けが話題になることがありますが、例えば TIdHTTP.Get メソッドではコードページの指定ができます。文字列の受信の際によく使用されている方法は、TMemoryStream 等で取得する方法です。TMemorsyStream には生のデータが格納さていますから、受信あるいは取得後にコードページを指定して文字列に変換できます。
基本的に画像等のバイナリデータは TStrema の派生クラスで送受信することになります。

コードページは以下のように、プログラム内でグローバルに設定しておくこともできます。



図10
Indy 10.6.2 で設定可能なコードページ

リスト1
Indy 10.6.2 でコードページをグローバルに設定する方法
implementation

uses
  IdGlobal,
  TypInfo;

{$R *.dfm}

//=============================================================================
//  Indey 10.6.2 における文字コード(コードページ)の設定
//
//  IdGlobalのメンバを使用するにはusesにIdGlobalを追加する
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  //文字コード(コードページ)の自動変換のグローバル設定
  //デフォルトはASCII
  IdGlobal.GIdDefaultTextEncoding := encOSDefault;  //範囲外の文字は破棄される
  IdGlobal.GIdDefaultTextEncoding := encASCII;      //範囲外の文字は破棄される
  IdGlobal.GIdDefaultTextEncoding := encUTF8;


end;

//=============================================================================
//  設定可能な文字コードの値のリスト
//  IdTextEncodingType(列挙型)の値を列挙
//
//  TyppeInfoの使用にはusesにTypInfoが必要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LpInfo : PTypeInfo;
  LpData : PTypeData;
  i      : Integer;
begin
  Memo1.Clear;

  LpInfo := TypeInfo(IdTextEncodingType);

  //列挙型であれば調査
  if LpInfo^.Kind = tkEnumeration then begin
    LpData := GetTypeData(LpInfo);
    for i := LpData^.MinValue to LpData^.MaxValue do begin
      Memo1.Lines.Add(GetEnumName(LpInfo, i));
    end;
  end;
end;


デコード、エンコードの指定は Indy 10.5.7 では TEncoding が使用できましたが、Indy 10.6.2 では専用の定数名を使用する方式に変更になっています。
下のコードはその使用例です。

URLEncode 関数と ParamsEncode 関数は / , . ( %2F %2C %2E ) 等をエンコードしませせん。パラメータの区切り文字である & もエンコードしません。



[備考]
Delphi XE7 以降の System.NetEncoding ユニットには、エンコードとデコード関係のクラスがいくつか実装されています。それらのクラスメソッドを使用してデコードやエンコードができます。


図11
デコードの例
図12
エンコードの例

リスト2
Indy 10.6.2 におけるデコードとエンコードの指定方法
このコードの動作確認は Windows 7 U64(SP1) + Delphi 10.2.3 Tokyo Community + Indy 10.6.2
implementation

uses
  IdURI,
  IdGlobal;

{$R *.dfm}

// =============================================================================
//  TIdURI.URLDecodeを使用したURL文字列のデコード
//  usesにIdURI,IdGlobalが必要
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LSrcStr : string;
  LDstStr : string;
begin
  Memo1.Lines.Clear;

  LSrcStr := '%E5%8D%B0%E5%88%B7%E3%80%80%E3%83%97%E3%83%AA%E3%83%B3%E3%82%BF';
  LDstStr := TIdURI.URLDecode(LSrcStr, IndyTextEncoding_UTF8);
  // 結果は'印刷 プリンタ'
  Memo1.Lines.Add(LSrcStr);
  Memo1.Lines.Add('');
  Memo1.Lines.Add(LDstStr);
end;

// =============================================================================
//  TIdURI.URLEncodeを使用したURL文字列のエンコード
//  TIdURI.URLEncodeはプロトコルがある文字列をエンコードする
//  プロトコルがないと変換に失敗する
//  usesにIdURI,IdGlobalが必要
// =============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LSrcStr : string;
  LDstStr : string;
begin
  Memo1.Lines.Clear;

  LSrcStr := 'http://www.test.com/印刷 プリンタ';
  LDstStr := TIdURI.URLEncode(LSrcStr, IndyTextEncoding_UTF8);

  //漢字部分の結果は'%E5%8D%B0%E5%88%B7%E3%80%80%E3%83%97%E3%83%AA%E3%83%B3%E3%82%BF'
  Memo1.Lines.Add(LSrcStr);
  Memo1.Lines.Add('');
  Memo1.Lines.Add(LDstStr);
end;

// =============================================================================
//  TIdURI.ParamsEncodeを使用した文字列のエンコード
//  usesにIdURI,IdGlobalが必要
// =============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
  LSrcStr : string;
  LDstStr : string;
begin
  Memo1.Lines.Clear;

  LSrcStr := '印刷 プリンタ';
  LDstStr := TIdURI.ParamsEncode(LSrcStr, IndyTextEncoding_UTF8);

  //結果は'%E5%8D%B0%E5%88%B7%E3%80%80%E3%83%97%E3%83%AA%E3%83%B3%E3%82%BF'
  Memo1.Lines.Add(LSrcStr);
  Memo1.Lines.Add('');
  Memo1.Lines.Add(LDstStr);
end;




08_Indy における User Agent ( ユーザエージェント ) の設定


ウェブページにアクセスする際、意味がある User Agent の設定情報がないとアクセスを拒否するサイトやウェブページがあります。
ウェブブラウザでアクセスする場合は、使用するブラウザが情報を持っています。実際にはウェブブラウザを使用しないので「偽装」ということになりますが、Indy を使用する場合は User Agent の値を明示的に設定する必要があります。User Agent の値は、以下のようにグローバルに設定することも、実際にアクセスする際に一時的に設定することもできます。

「偽装」ですから、どのウェブブラウザの設定を使用するかは任意です。



図13
実行時の User Agent 取得
  • IE 限定
  • この図は 64 ビット版の Windows 7 の IE 11

リスト3
Indy 10.6.2 における User Agent の設定
implementation

uses
  IdHTTPHeaderInfo,
  UrlMon;

{$R *.dfm}

//-----------------------------------------------------------------------------
//  UrlMonの関数を使用したIE のUser Agentの値の取得(1)
//  Ansi版,Unicode版のどちらのDelphiでも使用可能なようにAnsiCharを使用
//
//  usesにUrlMonが必要
//-----------------------------------------------------------------------------
function Get_IE_UserAgent: string;
var
  LUserAgent : array [0 .. MAX_PATH - 1] of AnsiChar;
  LdwSizeOut : DWord;
begin
  try
    LdwSizeOut := 0;
    FillChar(LUserAgent, SizeOf(LUserAgent), #0);
    UrlMkGetSessionOption(URLMON_OPTION_USERAGENT,
                          @LUserAgent,
                          SizeOf(LUserAgent),
                          LdwSizeOut,
                          0);
    Result := string(LUserAgent);
  except
    //Urlxxxの例外はシステム例外なので実際にはexceptでは補足できない
    on E: Exception do begin
      //Result := E.Message;
      Result := '';
    end;
  end;
end;

//-----------------------------------------------------------------------------
//  UrlMonの関数を使用したIE のUser Agentの値の取得(2)
//  Ansi版,Unicode版のどちらのDelphiでも使用可能なようにAnsiCharを使用
//
//  usesにUrlMonが必要
//-----------------------------------------------------------------------------
function Get_IE_ObtainUserAgent: string;
var
  LUserAgent : array [0 .. MAX_PATH - 1] of AnsiChar;
  LdwSizeOut : DWord;
begin
  Result := '';

  LdwSizeOut := SizeOf(LUserAgent);
  FillChar(LUserAgent, SizeOf(LUserAgent), #0);
  ObtainUserAgentString(0, @LUserAgent, LdwSizeOut);

  if LdwSizeOut > 0 then begin
    Result := string(LUserAgent);
  end;
end;

//=============================================================================
//  Indey 10.6.2 におけるUser-Agent(ユーザエージェント)の設定
//
//  GIdDefaultUserAgentの使用にはusesにIdHTTPHeaderInfoが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
const
  UserAgent = 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko';
var
  LText : string;
begin
  //グローバルに設定する場合
  //グローバル変数GIdDefaultUserAgentに代入しておく
  GIdDefaultUserAgent := UserAgent;

  //個別に設定する場合
  IdHTTP1.Request.UserAgent := UserAgent;

  //実行時にUser Agentの値を取得する例(IE限定)
  LText := Get_IE_UserAgent;
  MessageBox(Handle, PChar(LText), 'IE User Agent', MB_OK);
end;


ブラウザの User Agennt は、JavaScript を使用して、例えば以下のような HTML コードをブラウザで表示することで確認することができます。Uset Agent の値は、ブラウザの種類、あるいはリリース等によって異なる値になります。
この HTML コードで取得した値と、上の UrlMon の関数 で取得した値が必ずしも同じ値になるとは限りません。



リスト4
ウェブブラウザの User Agent を調べるための HTML コード
拡張子を .html にして保存する。保存のコードページは Shift-jis でも UTF-8 でもよい
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>UserAgent Sample</title>
</head>
<body>
<span id="userAgent"></span>

<script>
   var userAgent = window.navigator.userAgent;
   var element = document.getElementById("userAgent");
   element.innerText = userAgent;
</script>
</body>
</html>




09_Indy コンポーネントの仕様変更等


Indy はバージョンによって仕様の一部が変更されることがあります。
仕様の変更に伴う修正がわずらわしいからと、バージョンアップを避けることもできすが、問題がある現象の修正や新しい機能の利用はできないことになります。バージョンアップによる仕様の変更に対応していくことも重要ではないかと考えます。

例えばイベントの引数に変更があった場合、エラーとなります。そのような場合は、新しいバージョンでイベントを作成し直します。メソッドや関数、あるいはプロパティ等は、似たような機能と思われる名前で推測したりすることになるでしょう。





10_Delphi XE に Indy 10.6.2 インストール後に発生するエラー


Indy 10.6.2 は Delphi XE にもインストールできますが、避けた方が無難かも知れません。今回ダウンロードした Indy 10.6.2 - Berlin RTM にも、Delphi XE 用としてのインストール用パッケージグループもインストール用のバッチファイルも用意されていません。

インストール後に、Indy あるいは他のコンポーネントを配置したり、あるいは、既存のプロジェクトを開く時に以下のようなエラーが発生しました。このエラーが発生すると、フォームに配置したコンポーネントの一部が失われます。
これは、Delphi XE で実装された Windows Azure クラウド サービスを扱うためのコンポーネントのパッケージ dclWindowsAzureManagement150.bpl が原因で発生するようです。

筆者の場合、このパッケージの機能は使用しませんので、このパッケージを削除しました。[パッケージのインストール] で該当パッケージを削除しても削除できませんでした。そこで、レジストリのパッケージのリストからこのパッケージ名の項目を削除しました。


プロシージャ エントリ ポイント @Idheadercoderutf@initialization$qqrv がダイナミック リンク ライブラリ IndyProtocols150.bpl から見つかりませんでした。

パッケージ c:\program files (x86)\embarcadero\rad studio\8.0\bin\dclWindowsAzureManagement150.bpl を読み込めません。 指定されたプロシージャが見つかりません。



[備考]
Windows Azure 管理コンポーネントの登録名は、Delphi XE5 では「Embarcaderoクラウド管理コンポーネント」で、パッケージ名は dclCloudService190.bpl となってます。登録されているコンポーネントは TAmazonConnectionInfo, TAzureConnectionInfo の 2 つとなっています。



図14
Windows Azure 関係のエラー