旧Delphi FAQ – インターネット

Abstract: このQ&Aは、旧www.borland.co.jp に掲載されていた記事を転載したものです。記事は掲載時点の情報をあるがままに掲載しており、新バージョンでのご利用においては、コンポーネントやAPIの仕様変更等によりご利用いただけない場合がありますのでご留意ください。

    Internet の TFTP の Type メソッドが使用できないのは何故ですか?

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1

Q:
Internet の TFTP の Type メソッドが使用できないのは何故ですか?

A:
Delphi の予約語の Type と競合するために,TFTP.Type は TFTP.Type_ に変更されています。

    UDP によるデータ通信

該当するバージョン:Delphi 3.0/Delphi3.1

UDP(User Datagram Protcol) では,送信したデータが送信先に到達したかどうかの確認を行わないデータ通信を行います。

以下の例では,フォームに TUDP,TTable,そして TMemo を2つ配置しています。
Note1では,String 型へキャストを行っています。これは,AnsiString を持つバリアントをOleVariant へ代入したため WideString に変換されたためです。
Note2では,OleVariant 型の変数としています。
Note3では,OleVarant 型の変数に直接データを追加せずに,一旦 String 型の変数で受けます。
Table1.TableName , UDP1.LocalPort, および UDP1.RemotePort に適当な値を設定してください。

例)

     TableName       = 'Table1'
     UDP1.LocalPort  = 1;
     UDP1.RemotePort = 1;
   unit Unit1;

   interface

   uses
     Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
     StdCtrls, OleCtrls, DB, DBTables, ActiveX, isp3;

   type
     TForm1 = class(TForm)
       Memo1: TMemo;
       Memo2: TMemo;
       UDP1: TUDP;
       Table1: TTable;
       procedure FormClose(Sender: TObject; var Action: TCloseAction);
       procedure Memo2KeyDown(Sender: TObject; var Key: Word;
         Shift: TShiftState);
       procedure UDP1DataArrival(Sender: TObject; bytesTotal: Integer);
       procedure FormCreate(Sender: TObject);
     private
       { Private declarations }
     public
       { Public declarations }
     end;

   const
     MAXLINECOUNT = 2000;

   var
     Form1: TForm1;

   implementation

   {$R *.DFM}

   procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
   begin
     // ユーザーをコントロールテーブルから削除
     if NOT (Table1.State = dsInactive) then
       if Table1.FindKey( [string(UDP1.LocalIP)] ) then  // Note1 String へキャスト
         Table1.Delete;
   end;

   procedure TForm1.Memo2KeyDown(Sender: TObject; var Key: Word;
     Shift: TShiftState);
   var
     i : Integer;
     v : OleVariant;  // Note2
     S : String;
   begin
     if Key = VK_RETURN then
     begin
     {Get the data from the bottom memo and send it to
      each user listed in the control table.}
       Table1.Refresh;
       Table1.First;
       While NOT Table1.EOF do
       begin
         UDP1.RemoteHost := Table1.FieldByName( 'IP' ).AsString;
         S := '<' + UDP1.LocalHostName + '> ';     // Note3
         for i := 0 to Memo2.Lines.Count - 1 do
           s := s + Memo2.Lines[i];
         v := s;
         UDP1.SendData( v );
         Table1.Next;
       end;

       // データが送信されたら,下部のメモからデータを削除
       Memo2.Lines.Clear;
     end;
   end;

   procedure TForm1.UDP1DataArrival(Sender: TObject; bytesTotal: Integer);
   var
     v : OleVariant;
   begin
     // 受信データをメモに追加,MAXLINECOUNT を越える場合には,最初の行を削除
     UDP1.GetData( v, VT_BSTR );
     If Memo1.Lines.Count > MAXLINECOUNT then
       Memo1.Lines.Delete( 0 );
     Memo1.Lines.Add( v );
   end;

   procedure TForm1.FormCreate(Sender: TObject);
   var
     s : String;
     v : OleVariant;
   begin
     // アプリケーションのディレクトリ取得
     s := ExtractFilePath( Application.ExeName );
     // テーブルと Net File をアプリケーションのディレクトリに入れる
     Session.NetFileDir := s;
     With Table1 do
     begin
       DataBaseName := s;
      // テーブルが存在しない場合は,テーブルを作成
       try
         Open;
       except
         on E : EDBEngineError do
         begin
           if Pos( 'テーブルが存在しません', E.Message ) <> 0 then
           begin
             with FieldDefs do
             begin
               clear;
               Add( 'IP', ftString, 15, False );
               Add( 'Name', ftString, 25, False );
             end;
             With IndexDefs do
             begin
               Clear;
               Add( 'Indexname', 'IP', [ixPrimary] );
             end;
             CreateTable;
             Open
           end
          // テーブルが存在する場合は,例外を再生成
           else
             Raise E;
         end;
       end;

       // ユーザーをコントロールテーブルへ追加
       Insert;
       FieldByName( 'IP' ).AsString := UDP1.LocalIP;
       FieldByName( 'Name' ).AsString := UDP1.LocalHostName;
       Post;
     end;

     // 何らかのデータが送信されるまで TUDP コンポーネントは,OnDataArival
     // イベントを呼び出さない。ここでは,IP アドレス 127.0.0.1 を使用して
     // 有効なデータを送信します。
     UDP1.RemoteHost := '127.0.0.1';
     v := 'Welcome to ChatRm';
     UDP1.SendData( v );

     // OnDataArival イベントが実行されるようにする
     Application.ProcessMessages;

     // テキストのクリア
     Memo1.Lines.Clear;
   end;

   end.

    ウェブブラウザに指定の URL を開かせる

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

Q:
インストール済みのウェブブラウザに指定の URL を開かせるにはどうすればよいのですか?

A:
UrlMon ユニットで宣言されている HlinkNavigateString Win32 API を使います。

呼び出し例:

    HlinkNavigateString(Nil,'http://www.borland.co.jp/');

もし アクティブフォームの中から呼び出したい場合には以下のように指定します:

    HlinkNavigateString(ComObject,'http://www.borland.co.jp/');

ShellApi ユニットで宣言されている ShellExecute を使うこともできます。

    ShellExecute(0, 'open', 'http://www.borland.co.jp/', nil, nil, SW_SHOW);

    ソケットが 8K 以上のデータを受けないのは何故ですか?

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

Q:
TClientSocket と TserverSocket:
ソケットが 8K 以上のデータを受けないのは何故ですか?

A:
IP 層が,ストリームを 8K ごとに分割するからです。デベロッパは,明示的に長さを整数でストリームの最初に入れて,相手方に期待するデータ量を知らせます。
これは,何個の 8K パケットかと言うことです。

Socket コンポーネントは,WinSock のラッパーコンポーネントであり,ヘッダー情報(上記で延べたように)の付いたプロトコルではありません。デベロッパは,データのパディング(詰めること)に配慮する必要があります。以下のことが必要となります。

NOTE: 以下の事は,デベロッパによって異なります。一般的な事として述べます。

  1. 長さを指定する整数でソースのデータをパディングします。
  2. 受信側では,長さの整数を取り出します。
  3. 受信側では,受信したバイト数を数え,長さの整数と比較します。
  4. TotalBytesReceived <> LengthInteger の場合には,次のパケットは続きだと判り,そうでなければ,次のパケットは異なるストリームだと判ります。

NOTE: このことは,ヘッダ情報によって HTTP と FTP プロトコルによって処理されます('Content\Length')。

    ISAPI プログラムで大きいサイズの POST データを処理する方法について

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

Q:
ISAPI アプリケーションを作成しているのですが,大きなサイズのデータが POST された場合,Contents プロパティには,最初のデータしか格納されていません。
すべてのデータを読み込むには,どのようにしたらよいのでしょうか?

A:
ISAPI アプリケーションで大きな POST データを処理する場合には,WebActionItem の OnAction メソッドで,Contents プロパティに格納されていない残りのデータを ReadClient メソッドを使用し読み込む必要があります。
以下のコードを参考にしてください。

      procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;
      Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
      var
          LEN, Total : Integer;
          buf:  array[0..100000] of char;
      begin
             LEN := length(Request.Content);
             Total := LEN;
         Repeat
             LEN := Request.ReadClient(buf,100000);
             if LEN <> -1 then
                 Total := Total + LEN;
         until (LEN = -1) or (Total >= Request.ContentLength);

         // -1 の場合には,データがすべて Content に入っていることになります。
         //それ以外の場合には,分割されたデータとして入ってきますので,
         //分割して読み込んだデータをデータ中で結合するようにしてください。
      end;

    ローカルホスト名とIPアドレスを取得する方法を教えてください。 (99/01/08)

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
ローカルホスト名とIPアドレスを取得する方法を教えてください。

A:
ClientSocketコンポーネントやServerSocketコンポーネントを利用している場合には,各々のコンポーネントのSocketプロパティがありますので, そちらから取得する事が可能になっております。
また,ClientSoketコンポーネントやServerSocketコンポーネントを使用しない場合には,Windows APIを使用することにより可能になります。
下の例を参考にしてください。

    unit Unit1;
    interface
    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      WinSock, StdCtrls;

    type
      TForm1 = class(TForm)
        Button1: TButton;
        Memo1: TMemo;
        procedure Button1Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
      private
        { Private 宣言 }
      public
        { Public 宣言 }
      end;

    var
      Form1: TForm1;

    implementation

    {$R *.DFM}

    procedure TForm1.Button1Click(Sender: TObject);
    var
       p : PHostEnt;
       s : array[0..128] of char;
       p2: pchar;
    begin
       memo1.Lines.Clear;
       Gethostname(@s,128);
       p := GetHostByName(@s);
       Memo1.Lines.Add('HOSTNAME = '+p^.h_name);
       p2 := iNet_ntoa(PinAddr(p^.h_addr_list^)^);
       Memo1.Lines.Add('Local IP = '+ p2);
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    var
        wVersionRequested : WORD;
        wsaData : TWSAData;
    begin
         wVersionRequested := MAKEWORD(1,1);
         WSAStartup(wVersionRequested,wsaData);
    end;

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
        WSACleanup;
    end;
    end.

    CGI/ISAPIで作成したイメージやグラフをHTMLにそのまま表示するには、どのようにしたらよいのでしょうか? (99/2/3)

該当するバージョン:Delphi 3.0/Delphi3.1,Delphi4

Q:
CGI/ISAPIで作成したイメージやグラフをHTMLにそのまま表示するには,どのようにしたらよいのでしょうか?

A:
CGI/ISAPIで作成したイメージやグラフをHTMLに,そのまま表示する場合には,以下のようになります。
通常のイメージをHTMLに表示するのと同様に,HTML内の表示したい場所に<img>タグを設定します。
そこときのsrcは,送られてくるCGI/ISAPI名を指定します。

CGI/ISAPIプログラム内では,イメージデータをResposeによって送ることで実現できます。
例では,JPEGファイルをディスクから読み込み,それを表示するような,ISAPIプログラムになっていますので,これを参考にしていただきたいと思います。

HTMLの記述

    <html>
    <body>
    This is a TEST<BR>
    <img src="/cgi/project2.dll/picture">
    </body>
    </html>

Delphiのプログラム

  1. USESにJPEGを追加
  2. WebActionItemを追加し,PathInfoプロパティに/pictureを記述
  3. 追加したWebActionItemのOnActionイベントに以下のコードを記述する。
    procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;
      Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
    var
       JPG : TJpegImage;
       S :   TMemoryStream;
    begin
       JPG := TJpegImage.Create;
       try
           JPG.LoadFromFile('D:\BORLAND\Delphi40J\Help\Examples\Jpeg\testimg.jpg');
           S := TMemoryStream.Create;
           try
               JPG.SaveToStream(S);
               S.Position := 0;
               Response.ContentType := 'image/jpeg';
               Response.ContentStream := S;
               Response.SendResponse;
           finally
               S.Free;
           end;
       finally
           JPG.Free;
       end;
    end;

    ホスト名から IP アドレスを取得するには (98/07/01)

該当するバージョン:Delphi 2.0,Delphi 3.0/Delphi3.1,Delphi4

Q:
ホスト名から IP アドレスを取得するにはどうしたらいいですか。

A:
以下は,Edit1 に入力したホスト名から IP アドレスを取得し,Edit2 に表示する例です。uses 節には,WinSock を追加します。

procedure TForm1.Button1Click(Sender: TObject);
var
  wVersionRequired: Word;
  WSData: TWSAData;
  Status: Integer;
  Name: array[0..255] of Char;
  HostEnt: PHostEnt;
  IP: PChar;
begin
  wVersionRequired := MAKEWORD(1, 1);
  Status := WSAStartup(
        wVersionRequired, WSData);
  if Status <> 0 then begin
    MessageDlg(
      'Error Occured', mterror, [mbOK], 0);
    exit;
  end;
  StrPCopy(Name, Edit1.Text);
  HostEnt := GetHostByName(@Name);
  if HostEnt <> nil then begin
    IP := HostEnt^.h_addr_list^;
    Edit2.Text := IntToStr(Integer(IP[0]))
       + '.' + IntToStr(Integer(IP[1]))
       + '.' + IntToStr(Integer(IP[2]))
       + '.' + IntToStr(Integer(IP[3]));
  end
  else
    Edit2.Text := '(N/A)';
end;