4

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 共有ライブラリの識別にも問題がありました。これらの問題は、Delphi 2009 での Unicode 処理が原因で発生し、解決されました。私の Delphi 2009 コードは、実際の iTunes 共有ライブラリを識別し、その TXT レコードを照会することができます。機能していないのは、このサービス登録だけです。

私は愚かで明白な何かを見逃しているに違いありません。

誰かアイデアはありますか?!

アップデート

この問題に戻って、次のことを発見しました。

D2009 より前の IDE と D2009+ IDE を開いている場合 (D2006 と D2010 など)、同じプロジェクトを両方の IDE に同時にロードすると、次のようになります。

  • 2006 でビルドして実行: 動作します - 私のサービス アナウンスメントは iTunes で取り上げられます
  • D2010 に切り替えて実行 (ビルドなし): 最小限のコンパイル、実行、および動作を行います。
  • D2010 でフル ビルドを実行します。動作しなくなります

  • D2006 に切り替えて実行 (ビルドせずに): 動作しません

  • D2006 でフル ビルドを行う: 再び動作する

これは誰かに他のアイデアを与えますか?

4

4 に答える 4

5

これに対する答えは気が遠くなるようなものです。一方で、私は完全にばかげた、非常に単純な間違いを犯しましたが、他方では、私が見る限り、Delphi のどのバージョンでも動作するはずがありませんでした!

この問題は、文字列の Unicode/非 Unicode 性とは何の関係もありませんでしたが、実際には PORT パラメータの型の不一致が原因でした。

私はReverseBytes(Port)の結果を渡していました- そのパラメータはuint16_t、つまりWord値を期待していました。しかし、私のPortプロパティは (遅延して) Integerとして宣言されました!!

これを修正してPortをWordとして宣言すると、D2007 と D2009+ の両方のバージョンの Delphi で動作するようになりました。

とても奇妙です。

これに何らかの影響を与えた可能性のあるコンパイラの他のエッジケースの動作は、Unicode サポートが導入されたときに変更されたとしか思えません。

于 2010-08-20T03:20:09.427 に答える
1

ここで入手できる情報に基づくと、状況は次のとおりです。

  • Delphi 2007 でコードを使用して DLL を呼び出すと、1 つの結果が得られます。
  • Delphi 2009 のコードで同じ DLL を呼び出すと、別の結果が得られます。
  • 疑わしいのは、Delphi 2009 コンパイラに関連しているということです。

したがって、論理的には、違いは、Delphi 2009 が異なる値をパラメータとして送信することです。したがって、デバッグを完全に Delphi に依存しないようにするには、取得した値を報告するダミー DLL を作成する必要があります。関数呼び出しの DLL への逆アセンブルを確認し、それをデバッグして、両方のコンパイラでどの値がどのように DLL に渡されるかを正確に知るなど、他の Delphi 依存のメソッドを適用することもできます。

于 2009-09-28T07:03:07.877 に答える
0

あなたのコード サンプルには、vars "ServiceName" と "ServiceType" の宣言命令が見つかりません。

文字列型(したがってユニコード文字列)を想定すると、(はい...これをテストするために利用できるD2009はありません)怠惰な型キャストが問題になる可能性があります:

name  := ServiceName;

以下を使用しないのはなぜですか?

name  := PAnsiChar(AnsiString(ServiceName)) 

とにかく...ちょうど私の2セント。

ところで:私は常に事前定義された「EmptyStr」、「EmptyWideStr」を使用します...したがって、テストは次のようになります。

if (ServiceName <> EmptyStr) then

これは安全であり、型の混乱を避ける必要があります。

一方、Delphi は、次の宣言のように '' を ANSIChar として解釈する場合があります。

const
  MyParagraphChar = '§';

よくわかりません...私は混乱しています-今すぐ家に帰る必要があります;)

于 2009-10-14T16:18:21.730 に答える
-1

DLL が Delphi 2009 を使用して作成されていない場合は、PUTF8String 以外のものを使用することをお勧めします。Delphi 2009 の Utf8String 型は、Delphi 2007 の UTF8String 型とは異なります。

DLL が C/C++ を使用して記述されている場合は、PUtf8String の代わりに PAnsiChar() を使用することを強くお勧めします。

于 2009-09-27T17:37:03.730 に答える