在Delphi 7中运行的ZeroConf / Bonjour代码在2009年不工作
我对DNSServiceRegister有以下声明:
function DNSServiceRegister
(
var sdRef: TDNSServiceRef;
const flags: TDNSServiceFlags;
const interfaceIndex: uint32_t;
const name: PUTF8String; //* may be NULL */
const regType: PUTF8String;
const domain: PUTF8String; //* may be NULL */
const host: PUTF8String; //* may be NULL */
const port: uint16_t;
const txtLen: uint16_t;
const txtRecord: Pointer; //* may be NULL */
const callBack: TDNSServiceRegisterReply; //* may be NULL */
const context: Pointer //* may be NULL */
): TDNSServiceErrorType; stdcall; external DNSSD_DLL;
在我的Bonjour框架中,我对已宣布的服务进行了以下响应(即,通过Bonjour实际开始宣布自己):
procedure TAnnouncedService.Activate;
var
flags: Cardinal;
name: UTF8String;
svc: UTF8String;
pn: PUTF8String;
ps: PUTF8String;
begin
fPreAnnouncedServiceName := ServiceName;
inherited;
if AutoRename then
flags := 0
else
flags := kDNSServiceFlagsNoAutoRename; { - do not auto-rename }
if (ServiceName <> '') then
begin
name := ServiceName;
pn := PUTF8String(name);
end
else
pn := NIL;
svc := ServiceType;
ps := PUTF8String(svc);
CheckAPIResult(DNSServiceRegister(fHandle,
flags,
0 { interfaceID - register on all interfaces },
pn,
ps,
NIL { domain - register in all available },
NIL { hostname - use default },
ReverseBytes(Port),
0 { txtLen },
NIL { txtRecord },
DNSServiceRegisterReply,
self));
TBonjourEventHandler.Create(fHandle);
end;
这比我认为的严格要求更为冗长,当然它在Delphi 7中的工作方式非常完美,并且具有非常简洁的形式。 为了便于调试,我将很多操作扩展为明确的步骤,例如,能够识别Delphi 2009中可能出现的“隐藏”字符串有效载荷的隐式转换。
即使在这种不整洁的扩展形式中,此代码也可以在Delphi 7中编译和运行,但如果我使用Delphi 2009进行编译和运行,则不会公布我的服务。
例如,如果我将此代码作为Delphi 7应用程序的一部分运行以注册_daap._tcp
服务(iTunes共享库),我会在运行的iTunes实例中看到它弹出。 如果我在没有修改的情况下在Delphi 2009中重新编译完全相同的应用程序并运行它,我没有看到我的服务出现在iTunes中。
在使用dns-sd命令行实用程序进行监视时,我会得到相同的行为。 也就是说,使用Delphi 7编译的服务代码与我预期的一样,在Delphi 2009中编译 - 没有任何问题。
我没有收到Bonjour API的任何错误 - DNSServiceRegisterReply回调函数的ErrorCode为0(零),即成功,并且如果我在标志中指定的AutoRename中提供一个NIL名称参数,那么我的服务将被分配正确默认名称。 但该服务仍未在iTunes中显示。
我对正在发生的事情感到不知所措。
正如你从代码的扩展中可以看出的一样,我一直在追逐Delphi 2009中Unicode实现引入的潜在错误,但这似乎并没有引起我的注意。
该代码最初是针对Bonjour API / SDK 1.0.3版开发的。 我已经更新到1.0.6,以防万一,但没有任何成功。 afaict 1.0.6只是增加了一个新的功能来获取“属性”,目前只支持获取Bonjour版本的“DaemonVersion”属性 - 这是完美的。
注意:我知道代码在Delphi 7中并不是技术上UTF8安全的 - 我尽可能地消除了显式转换,以便尽可能简化Delphi 2009应用的自动转换。 我现在的目标是在Delphi 2009中实现这个功能,然后从该解决方案中反向工作,希望找到适用于早期版本Delphi的兼容方法。
还请注意:我最初在浏览广告服务时也遇到了问题,即在网络上识别实际的iTunes共享库。 这些问题是由德尔福2009年的Unicode处理引起的,并已得到解决。 我的Delphi 2009代码就像能够识别实际的iTunes共享库并查询它的TXT记录一样。 只有这个服务注册不起作用。
我必须失去一些愚蠢和明显的东西。
有没有人有任何想法?
UPDATE
回到这个问题后,我发现了以下内容:
如果我有一个预置的D2009和一个D2009 + IDE打开(例如D2006和D2010),并且这两个IDE同时载入同一个项目:
在D2010中完整构建:停止工作
切换回D2006并运行(无建筑物):不起作用
这是否给任何人任何其他想法?
对此的答案令人难以置信。 一方面,我犯了一个完全愚蠢的,非常简单的错误,但另一方面,它绝不应该 - 在我看到的情况下 - 在Delphi的任何版本中工作过!
这个问题与任何字符串的Unicode /非Unicode相关,但实际上是由于PORT参数中的类型不匹配造成的。
我正在传入ReverseBytes(Port)的结果 - 该参数需要一个uint16_t ,即一个Word值。 然而,我的端口属性被声明为( 整数 ) 整数 !
一旦我解决了这个问题并将Port声明为Word ,它现在可以在Delphi的D2007和D2009 +版本上运行。
很奇怪。
我只能认为,当引入Unicode支持时,编译器的某些其他边缘行为可能会以某种方式影响到这一点。
根据我们在此提供的信息,情况是这样的:
从逻辑上说,差异必须是,德尔福2009发送不同的值作为参数。 为了使调试真正实现Delphi独立,您需要创建一个虚拟DLL,它报告它获取的值。 其他依赖于Delphi的方法可能会被应用,例如查看将函数调用反汇编到DLL中,并调试它,以便我们确切知道在两个编译器中传递了哪些值以及如何传递给DLL。
我找不到代码示例中变量“ServiceName”和“ServiceType”的声明指令。
假设一个字符串类型(因此是一个Unicode字符串),我猜(是的...没有D2009可用来测试这个)懒类型转换可能是一个问题:
name := ServiceName;
为什么不使用以下内容?
name := PAnsiChar(AnsiString(ServiceName))
无论如何...只是我的2 cts。
顺便说一句:我总是使用预先定义的“EmptyStr”,“EmptyWideStr”...所以测试看起来像:
if (ServiceName <> EmptyStr) then
这应该是安全的,避免类型的混淆。
另一方面,德尔福可能会像下面的声明那样将ANS解释为ANSIChar:
const
MyParagraphChar = '§';
不知道...我很困惑 - 现在应该回家;)
链接地址: http://www.djcxy.com/p/91049.html上一篇: ZeroConf/Bonjour Code that works in Delphi 7 not working in 2009