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: 以下の事は,デベロッパによって異なります。一般的な事として述べます。
- 長さを指定する整数でソースのデータをパディングします。
- 受信側では,長さの整数を取り出します。
- 受信側では,受信したバイト数を数え,長さの整数と比較します。
- 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のプログラム
- USESにJPEGを追加
- WebActionItemを追加し,PathInfoプロパティに/pictureを記述
- 追加した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;