在Delphi 7中工作的ZeroConf / Bonjour代码在2009年不工作 [英] ZeroConf/Bonjour Code that works in Delphi 7 not working in 2009

查看:147
本文介绍了在Delphi 7中工作的ZeroConf / Bonjour代码在2009年不工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对DNSServiceRegister有以下声明:

 函数DNSServiceRegister 

var sdRef:TDNSServiceRef ;
const flags:TDNSServiceFlags;
const interfaceIndex:uint32_t;
const名称:PUTF8String; // *可能为NULL * /
const regType:PUTF8String;
const域:PUTF8String; // *可能为NULL * /
const host:PUTF8String; // *可能为NULL * /
const port:uint16_t;
const txtLen:uint16_t;
const txtRecord:Pointer; // *可能为NULL * /
const callBack:TDNSServiceRegisterReply; // *可能为NULL * /
const上下文:指针// *可能为NULL * /
):TDNSServiceErrorType;标准外部DNSSD_DLL;

在我的Bonjour框架中,我已经对宣布的服务进行了以下响应(即实际启动通过Bonjour宣布):

 程序TAnnouncedService.Activate; 
var
flags:Cardinal;
名称:UTF8String;
svc:UTF8String;
pn:PUTF8String;
ps:PUTF8String;
begin
fPreAnnouncedServiceName:= ServiceName;

继承;

如果AutoRename然后
标志:= 0
else
标志:= kDNSServiceFlagsNoAutoRename; { - 不要自动重命名}

if(ServiceName<>'')然后
begin
name:= ServiceName;
pn:= PUTF8String(name);
end
else
pn:= NIL;

svc:= ServiceType;
ps:= PUTF8String(svc);

CheckAPIResult(DNSServiceRegister(fHandle,
flags,
0 {interfaceID - 在所有接口上注册),
pn,
ps,
NIL {domain-register in all available},
NIL {hostname - use default},
ReverseBytes(Port),
0 {txtLen},
NIL {txtRecord},
DNSServiceRegisterReply,
self));
TBonjourEventHandler.Create(fHandle);
结束

这比我认为是严格需要的更为冗长,当然它在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只是添加了一个新的功能来获取属性,目前它只支持一个DaemonVersion属性来获取Bonjour版本 - 这是完美的。



注意:我知道,在Delphi 7中,代码不是技术上的UTF8安全 - 我尽可能地消除了明确的转换,以使事情尽可能简单用于Delphi 2009适用的自动转换。我的目标是让Delphi在2009年工作,然后从该解决方案中退出,希望能够为早期版本的Delphi找到兼容的方法。



另请注意:我最初也在浏览广告服务时遇到问题,即在网络上识别一个实际的iTunes共享库。这些问题是由Delphi 2009中的Unicode处理引起的,已经解决了。我的Delphi 2009代码就像能够识别一个实际的iTunes共享库并查询它的TXT记录一样。只有这个服务注册不起作用。



我必须缺少一些愚蠢和明显的东西。



有没有人有任何想法?



更新



回到这个问题我现在发现了以下内容:



如果我有一个pre-D2009和一个D2009 + IDE打开(例如D2006和D2010)与相同项目同时加载到两个IDE中:




  • 在2006年之前构建并运行:它的工作原理 - 我的服务公告由iTunes拾取

  • 切换到D2010并运行(不建立):它执行最少的编译,运行和工作。

  • 在D2010中完成构建:停止


  • 切换回D2006并运行(不构建):不起作用


  • 在D2006中做一个完整的构建:它再次工作



这是否给任何其他任何想法?

解决方案

Th这回答是令人难以置信的。一方面,我做出了一个完全愚蠢的,非常简单的错误,但另一方面它绝对不可能 - 据我所见 - 在任何版本的Delphi中都可以使用。



问题与任何字符串的Unicode /非单一性无关,但实际上是由于PORT参数中的类型不匹配。



我正在传递 ReverseBytes(端口)的结果 - 该参数预期为 uint16_t ,即 Word 值。然而,我的端口属性声明(懒惰)为整数 !!



一旦我修复了这个, strong>端口声明为 Word ,现在可以在D2007和D2009 +版本的Delphi上工作。



很奇怪。



我只能认为,在引入Unicode支持时,编译器的某些其他边缘行为可能会以某种方式受到影响。


I have the following declaration for 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;

In my Bonjour framework I have the following response to an announced service being made active (i.e. to actually start announcing itself, via 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;

This is more verbose than I think it strictly needs to be, certainly it was working perfectly well in Delphi 7 in a much less verbose form. I have expanded a lot of operations into explicit steps to facilitate debugging, e.g. to be able to identify any implicit transforms of string payloads that may be occuring "under the hood" in Delphi 2009.

Even in this untidy expanded form this code compiles and works perfectly well in Delphi 7, but if I compile and run with Delphi 2009 I get no announcement of my service.

For example, if I run this code as part of a Delphi 7 application to register a _daap._tcp service (an iTunes shared library) I see it pop-up in a running instance of iTunes. If I recompile the exact same application without modification in Delphi 2009 and run it, I do not see my service appearing in iTunes.

I get the same behaviour when monitoring with the dns-sd command line utility. That is, service code compiled with Delphi 7 behaves as I expect, compiled in Delphi 2009 - nothing.

I am not getting any errors from the Bonjour API - the DNSServiceRegisterReply callback is being called with an ErrorCode of 0 (zero), i.e. success, and if I supply a NIL name parameter with AutoRename specified in the flags then my service is allocated the correct default name. But still the service does not show up in iTunes.

I am at a loss as to what is going on.

As you might be able to tell from the expansion of the code, I have been chasing potential errors being introduced by the Unicode implementation in Delphi 2009, but this seems to be leading me nowhere.

The code was originally developed against version 1.0.3 of the Bonjour API/SDK. I've since updated to 1.0.6 in case that was somehow involved, without any success. afaict 1.0.6 merely added a new function for obtaining "properties", which currently supports only a "DaemonVersion" property for obtaining the Bonjour version - this is working perfectly.

NOTE: I'm aware that the code as it stands is not technically UTF8-safe in Delphi 7 - I have eliminated explicit conversions as far as possible so as to keep things as simple as possible for the automatic conversions that Delphi 2009 applies. My aim now is to get this working in Delphi 2009 then work backward from that solution to hopefully find a compatible approach for earlier versions of Delphi.

NOTE ALSO: I originally also had problems with browsing for advertised services, i.e. identifying an actual iTunes shared library on the network. Those issues were caused by the Unicode handling in Delphi 2009 and have been resolved. My Delphi 2009 code is just as capable of identifying an actual iTunes shared library and querying it's TXT records. It's only this service registration that isn't working.

I must be missing something stupid and obvious.

Does anyone have any ideas?!

UPDATE

Having returned to this problem I have now discovered the following:

If I have a pre-D2009 and a D2009+ IDE open (e.g D2006 and D2010) with the same project loaded into both IDE's concurrently:

  • Build and run under 2006: It works - my service announcement is picked up by iTunes
  • Switch to D2010 and run (without building): It does a minimal compile, runs and works.
  • Do a full build in D2010: It stops working

  • Switch back to D2006 and run (without building): It doesn't work

  • Do a full build in D2006: It works again

Does this give anyone any other ideas?

解决方案

The answer to this is mind boggling. On the one hand I made a completely stupid, very simple mistake, but on the other hand it should never - as far as I can see - have worked in ANY version of Delphi!

The problem was nothing what-so-ever to do with the Unicode/non-unicodeness of any strings, but was actually due to a type mismatch in the PORT parameter.

I was passing in the result of ReverseBytes(Port) - that parameter expected a uint16_t, i.e. a Word value. My Port property was however declared (lazily) as an Integer!!

Once I fixed this and had Port declared as a Word, it now works on both D2007- and D2009+ versions of Delphi.

Very weird.

I can only think that some other edge-case behaviour of the compiler that might have somehow affected this was changed when Unicode support was introduced.

这篇关于在Delphi 7中工作的ZeroConf / Bonjour代码在2009年不工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆