Delphi开发Web程序问题解答
周立军
问题:如何从Web
Server Application中返回一幅图像?
答:Web Server Application不仅可以生成复杂的页面文档,也可以根据用户请求返回不同的图像。当然有比较简单的方法,根据输入参数的不同,〈img
src...〉标记也指向不同的URL地址。这里我们不用这个办法,而是利用DLL返回图像。
首先建立一个页面容器(Page Producer),内容如下:
〈html〉
〈body〉This is a test〈BR〉〈img src="/scripts/mydll.dll/picture"〉〈/body〉
〈/html〉
接下来设定对应于PathInfo的动作事件,返回图像结果,源代码如下(注意:单元声明中要包含JPEG单元):
procedure TWebModule1.WebModule1WebActionItem1Action(Sender:
TObject;Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
Jpg: TJpegImage;
S: TMemoryStream;
begin
Jpg := TJpegImage.Create;
try
Jpg.LoadFromFile(′test′);
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;
实际上用这种方法和前面提到的简单做法相比,具有更安全和更灵活的特点。以此为基础稍加修改可以产生一般开发工具难以实现的效果。
问题:为什么在ISAPI/NSAPI动态连接库(DLL)中使用本地数据库驱动程序(Native
Access Driver)会报错,该如何解决?
答:因为DAO 3.0 或者DAO 3.5是所谓Thread-Safe(线程安全程序),而一个Web服务器(例如IIS)会随用户请求产生多个线程,同时把ISAPI对应的DLL也列为线程。这时ISAPI就会通过BDE通知DAO,告诉它不符合线程安全规定。
如果你一定要访问Access 95/97库,那么可以通过ODBC访问。ODBC不会经过DAO,而且也是一个线程安全程序。此外还有一些第三方的控件集,通过它们可以直接由BDE访问Access
95/97,效率更高。
问题:用户访问我Web服务器上的ISAPI DLL,可是报告:“Invalid
filename”(无效的文件名),然而该文件的确存在。对了,我的数据库在一台Novell
服务器上。这是为什么呢?
答:你没有设定对应于你IUSR_XXX账户的驱动器路径映射(MAPING)。因为Novell不是采用FAT,所以要手工添加路径映射。当然,可以做成开机登录脚本。请牢记,如果你运行IIS作为Web服务器,而又涉及Novell,无论作为文件服务器或数据库服务器,都要定义好路径映射。
问题:当我设置一个ODBC DSN,并通过它访问ISAPI/NSAPI服务器时就出现错误:“Invalid
configuration parameter for alias {alias_name}”(无效的别名配置),这是为什么?
答:你如果要为访问的用户(IIS用户)建立一个ODBC别名,那么要注意创建一个System
DSN(系统DNS),而不要创建“用户DNS”,虽然“用户DNS”是缺省设定,否则就会出现如上错误提示。
问题:在Delphi 3中为何不能创建真正的多线程DLL?
答:虽然Delphi 3中的ISAPI DLL向导已经为创建多线程DLL生成了大量代码,可还是有一个严重的缺陷:没有申明本应用程序是一个多线程的程序。所以需要你添加一句话:
IsMultiThread := TRUE;
把这句话放在DPR程序begin-end的开始处,使之成为第一句。
问题:如何取得客户机(访问机器)的名称和IP地址?
答:实现这个功能用TCP控件来做非常容易。从Internet页面上选取一个TCP控件,然后就直接可以得到你所需要的:
Memo1.Lines.Add(TCP1.LocalHostName);
Memo1.Lines.Add(TCP1.LocalIp);
当然,如果你不希望这样做,还有比较复杂的办法:
uses Winsock;
procedure TForm1.FormCreate(Sender: TObject);
var
wVersionRequested : WORD;
wsaData : TWSAData;
begin
{创建 WinSock}
wVersionRequested := MAKEWORD(1, 1);
WSAStartup(wVersionRequested, wsaData);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
p : PHostEnt;
s : array[0..128] of char;
p2 : pchar;
begin
{得到计算机名称}
GetHostName(@s,128);
p:=GetHostByName(@s);
Memo1.Lines.Add(p^.h_Name);
{得到机器IP地址}
p2 := iNet_ntoa(PInAddr(p^.h_addr_list^)^);
Memo1.Lines.Add(p2);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
{释放 WinSock}
WSACleanup;
end;
这是一个调用了WinSock的独立单元,你可以把它直接嵌入到你的程序中去。
问题:如何得知现在是否和Internet连接?
答:最简单的办法是用一个TCP元件得到自己当前的IP,通过判断IP得知是否连入Internet。例如:
if TCP1.LocalIp = '0.0.0.0' then
ShowMessage('目前没有连入Internet!');
因为Internet和Intranet没本质区别,所以一般不能判定是和Internet连接还是仅仅连入Intranet。当然。你也可以再加一个PING元件,去PING一个比较稳定、速度较快的站点,如果连通则表明已经接入Internet。不过这种办法通用性不好。
问题:如何打印一个Web页面?
答:可以选用HTML控件的AutoPrint方法。例如:
uses Printers;
procedure TForm1.Button1Click(Sender: TObject);
var
OldCur: TCursor;
begin
OldCur := Screen.Cursor;
with Printer do
begin
BeginDoc;
HTML1.AutoPrint(handle);
Title := HTML1.URL;
EndDoc;
end;
Screen.Cursor := OldCur;end;
此外还可以利用其PrintPage方法。不过我推荐你采用AutoPrint,因为这样控制更灵活,可以过滤一些你不希望打印的内容。