Похоже, что Apple Bonjour SDK не устанавливает TXTRecord при публикации сервиса из-за взаимодействия COM / .NET.
Вкратце, есть класс COM для создания текстовой записи:
[
odl,
uuid(8FA0889C-5973-4FC9-970B-EC15C925D0CE),
helpstring("ITXTRecord Interface"),
dual,
nonextensible,
oleautomation
]
interface ITXTRecord : IDispatch {
[id(0x00000001), helpstring("method SetValue")]
HRESULT SetValue(
[in] BSTR key,
[in] VARIANT value);
...
};
[
uuid(AFEE063C-05BA-4248-A26E-168477F49734),
helpstring("TXTRecord Class")
]
coclass TXTRecord {
[default] interface ITXTRecord;
};
Соответствующий код C ++ находится там: https://github.com/Apple-FOSS-Mirror/mDNSResponder/blob/master/mDNSWindows/DLLX/TXTRecord.cpp#L38
И есть способ регистрации сервиса в классе IDNSSDService
:
[id(0x00000004), helpstring("method Register")]
HRESULT Register(
[in] DNSSDFlags flags,
[in] unsigned long ifIndex,
[in] BSTR name,
[in] BSTR regtype,
[in] BSTR domain,
[in] BSTR host,
[in] unsigned short port,
[in] ITXTRecord* record,
[in] IDNSSDEventManager* eventManager,
[out, retval] IDNSSDService** service);
Соответствующий метод C ++ есть: https://github.com/Apple-FOSS-Mirror/mDNSResponder/blob/master/mDNSWindows/DLLX/DNSSDService.cpp#L494
Тогда в .NET:
let txtRecord = new TXTRecordClass()
txtRecord.SetValue("test", "test")
_service.Register(enum<DNSSDFlags>(0), uint32(0), author, "_webdav._tcp", null, null, uint16(80), txtRecord, _events)
SetValue работает хорошо, и был вызван метод CTXTRecord :: SetValue. Указатель this
скажем, 0x004573ec.
Сложность в том, что указатель на record
в методе Register
отличается и не равен 0x004573ec! Он указывает на какой-то другой адрес, обычно недалеко от сохраненного указателя (0x004573ec). Хорошо, может быть, это какая-то обертка. Плохо то, что Publish
позже брось это CComObject<CTXTRecord>*
но похоже, что указанный объект не инициализирован (имеет нулевые поля). Я пытался использовать разные подходы, такие как передача txtRecord
По ссылке ищите обходной путь, но здесь ничего нет.
Похоже, что в IDL отсутствует пропущенная директива или подход, реализованный в Publish
неверно, но мои навыки взаимодействия с .NET / C ++ / COM недостаточно хороши, чтобы найти решение. Есть идеи?
Эта оболочка COM имеет действительно безобразный хак:
STDMETHODIMP CDNSSDService::Register(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, BSTR host, USHORT port, ITXTRecord *record, IDNSSDEventManager *eventManager, IDNSSDService **service)
{
// ...
if ( record )
{
CComObject< CTXTRecord > * realTXTRecord;
realTXTRecord = ( CComObject< CTXTRecord >* ) record;
// ...
}
// ...
}
Который обречен на провал с маршалированными указателями интерфейса, из объектов, которые принадлежат другой квартире. Я полагаю, ваш ITXTRecord
создается в другом процессе, то есть в другой квартире, так что приведение принимает COM-прокси вместо реального объекта.
Один из способов обойти это — найти способ получить ссылку на TXTRecord
объект, созданный COM-сервером. Я нашел два места в оболочке COM (Вот а также Вот), которые создают объект и два места (Вот а также Вот) где этот объект предоставляется клиенту.
Следуя ссылкам, кажется, вы должны позвонить или 1. CDNSSD::Resolve
с IResolveListener
или жеCDNSSDService::Resolve
с IDNSSDEventManager
, указывая на объект, который также реализует _IDNSSDEvents
(это может быть ваш собственный объект), который получит «реальный» ITXTRecord
в качестве аргумента ServiceResolved
метод события.
Таким образом, вы можете сделать фиктивное решение с помощью интеллектуального обработчика событий, который захватывает TXTRecord
, Если вы найдете надежный хост (например, localhost или 127.0.0.1), вы, возможно, превратите его в фабричный метод. На самом деле я не проверял это, но из кода, если на хосте нет записи TXT, вы просто получите пустую.
IResolveListener
и декларация CDNSSD
сам.