mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
730 lines
15 KiB
730 lines
15 KiB
|
|
#include "precomp.h"
|
|
#ifdef IP_OBEX
|
|
|
|
//#include <atlconv.h>
|
|
|
|
#include "dynamlnk.h"
|
|
#include <malloc.h>
|
|
|
|
#include <ssdp.h>
|
|
#define IMPL
|
|
|
|
// dynamic DLL stuff for SSDP
|
|
typedef enum _SsdpApiIndex
|
|
{
|
|
SSDP_REGISTER_SERVICE = 0,
|
|
SSDP_DEREGISTER_SERVICE,
|
|
SSDP_STARTUP,
|
|
SSDP_FIND_SERVICES,
|
|
SSDP_GET_FIRST_SERVICE,
|
|
SSDP_GET_NEXT_SERVICE,
|
|
SSDP_FIND_SERVICES_CLOSE,
|
|
SSDP_CLEANUP,
|
|
SSDP_REGISTER_NOTIFICATION,
|
|
SSDP_DEREGISTER_NOTIFICATION,
|
|
SSDP_CLEANUP_CACHE,
|
|
};
|
|
|
|
// not subject to localization
|
|
static LPCSTR g_apchFunctionNames[] = {
|
|
"RegisterService",
|
|
"DeregisterService",
|
|
"SsdpStartup",
|
|
"FindServices",
|
|
"GetFirstService",
|
|
"GetNextService",
|
|
"FindServicesClose",
|
|
"SsdpCleanup",
|
|
"RegisterNotification",
|
|
"DeregisterNotification",
|
|
"CleanupCache",
|
|
NULL
|
|
};
|
|
|
|
//
|
|
// NOTE: i have copied the following structs and defines
|
|
// so that we are not dependant on the SSDP headers, most of
|
|
// which we weren't using.
|
|
|
|
//
|
|
// from ssdp.h
|
|
//
|
|
typedef struct _SSDP_MESSAGE
|
|
{
|
|
/* [string] */ LPSTR szType;
|
|
/* [string] */ LPSTR szLocHeader;
|
|
/* [string] */ LPSTR szAltHeaders;
|
|
/* [string] */ LPSTR szUSN;
|
|
/* [string] */ LPSTR szSid;
|
|
DWORD iSeq;
|
|
UINT iLifeTime;
|
|
/* [string] */ LPSTR szContent;
|
|
} SSDP_MESSAGE;
|
|
|
|
typedef struct _SSDP_MESSAGE *PSSDP_MESSAGE;
|
|
|
|
typedef enum _NOTIFY_TYPE {
|
|
NOTIFY_ALIVE,
|
|
NOTIFY_PROP_CHANGE
|
|
} NOTIFY_TYPE;
|
|
|
|
typedef enum _SSDP_CALLBACK_TYPE {
|
|
SSDP_FOUND = 0,
|
|
SSDP_ALIVE = 1,
|
|
SSDP_BYEBYE = 2,
|
|
SSDP_DONE = 3,
|
|
SSDP_EVENT = 4,
|
|
SSDP_DEAD = 5,
|
|
} SSDP_CALLBACK_TYPE, *PSSDP_CALLBACK_TYPE;
|
|
|
|
typedef void (WINAPI *SERVICE_CALLBACK_FUNC)(SSDP_CALLBACK_TYPE CallbackType,
|
|
CONST SSDP_MESSAGE *pSsdpService,
|
|
void *pContext);
|
|
//
|
|
// from ssdperror.h
|
|
//
|
|
#define SSDP_ERROR_BASE 18000
|
|
#define ERROR_NO_MORE_SERVICES SSDP_ERROR_BASE+1
|
|
|
|
//
|
|
// end copy header
|
|
//
|
|
|
|
typedef HANDLE (*REGISTERSERVICE) (PSSDP_MESSAGE, DWORD);
|
|
typedef BOOL (*DEREGISTERSERVICE) (HANDLE, BOOL);
|
|
typedef BOOL (*SSDPSTARTUP) ();
|
|
typedef HANDLE (*FINDSERVICES) (char *, void *, BOOL);
|
|
typedef BOOL (*GETFIRSTSERVICE) (HANDLE, PSSDP_MESSAGE *);
|
|
typedef BOOL (*GETNEXTSERVICE) (HANDLE, PSSDP_MESSAGE *);
|
|
typedef BOOL (*FINDSERVICESCLOSE) (HANDLE);
|
|
typedef void (*SSDPCLEANUP) ();
|
|
typedef HANDLE (*REGISTERNOTIFICAION) (NOTIFY_TYPE, char *, char *, SERVICE_CALLBACK_FUNC,void *);
|
|
typedef BOOL (*DEREGISTERNOTIFICAION) (HANDLE);
|
|
typedef BOOL (*CLEANUPCACHE) ();
|
|
|
|
|
|
|
|
DynamicDLL g_SsdpDLL( TEXT("SSDPAPI.DLL"), g_apchFunctionNames );
|
|
|
|
#define USES_CONVERSION int _convert = 0; _convert; UINT _acp = CP_ACP; _acp; LPCWSTR _lpw = NULL; _lpw; LPCSTR _lpa = NULL; _lpa
|
|
|
|
inline LPSTR WINAPI AtlW2AHelper(LPSTR lpa, LPCWSTR lpw, int nChars, UINT acp)
|
|
{
|
|
// verify that no illegal character present
|
|
// since lpa was allocated based on the size of lpw
|
|
// don't worry about the number of chars
|
|
lpa[0] = '\0';
|
|
WideCharToMultiByte(acp, 0, lpw, -1, lpa, nChars, NULL, NULL);
|
|
return lpa;
|
|
}
|
|
|
|
#define W2A(lpw) (\
|
|
((_lpw = lpw) == NULL) ? NULL : (\
|
|
_convert = (lstrlenW(_lpw)+1)*2,\
|
|
AtlW2AHelper((LPSTR) alloca(_convert), _lpw, _convert, _acp)))
|
|
|
|
#define Trace0 DbgPrint
|
|
#define Trace1 DbgPrint
|
|
#define Trace2 DbgPrint
|
|
#define Trace3 DbgPrint
|
|
#define Trace4 DbgPrint
|
|
|
|
DWORD
|
|
DeviceChangeWorker(
|
|
PVOID Context
|
|
);
|
|
|
|
|
|
|
|
#define T2A W2A
|
|
|
|
const WCHAR *c_szObex= TEXT("OBEX");
|
|
|
|
BOOL
|
|
RegisterWithSsdp(
|
|
const in_addr *IpAddress,
|
|
SOCKET *listenSocket,
|
|
HANDLE *SsdpHandle,
|
|
DWORD dwPort
|
|
)
|
|
|
|
{
|
|
SOCKET sock = INVALID_SOCKET;
|
|
sockaddr_in saListen = {0};
|
|
int nRet = 0;
|
|
TCHAR szHostNameW[MAX_PATH];
|
|
SSDP_MESSAGE message = {0};
|
|
DWORD dwFlags = 0, dwSize;
|
|
HRESULT hr;
|
|
char szPort[MAX_PATH];
|
|
char * pszAddr;
|
|
|
|
USES_CONVERSION;
|
|
|
|
//
|
|
// establish listen socket
|
|
//
|
|
sock = socket( AF_INET, SOCK_STREAM, 0 );
|
|
|
|
if ( sock == INVALID_SOCKET )
|
|
{
|
|
Trace2( "RegisterWithSsdp - socket() for port 0x%lx failed! 0x%lx\n", dwPort);
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// now get ready to bind it to the address
|
|
//
|
|
saListen.sin_addr=*IpAddress;
|
|
saListen.sin_family = AF_INET;
|
|
saListen.sin_port = (short) dwPort;
|
|
|
|
nRet = bind( sock, (const struct sockaddr *)&saListen, sizeof(saListen) );
|
|
|
|
if( nRet == SOCKET_ERROR ) {
|
|
|
|
Trace2( "RegisterWithSsdp - bind on port 0x%lx failed! 0x%lx\n", dwPort, WSAGetLastError());
|
|
goto Error;
|
|
}
|
|
|
|
// set socket into listening mode
|
|
nRet = listen( sock, 2 );
|
|
if ( nRet == SOCKET_ERROR ) {
|
|
|
|
Trace2( "RegisterWithSsdp - listen on port 0x%lx failed! 0x%lx\n", dwPort, WSAGetLastError());
|
|
goto Error;
|
|
}
|
|
|
|
// register with SSDP so other people can find us
|
|
_itoa(dwPort, szPort, 10);
|
|
// gethostname(szHostName, sizeof(szHostName));
|
|
dwSize = sizeof(szHostNameW);
|
|
GetComputerNameEx(ComputerNameDnsFullyQualified, szHostNameW, &dwSize);
|
|
|
|
|
|
pszAddr = inet_ntoa(*IpAddress);
|
|
|
|
// now fill in the struct
|
|
message.szType = T2A(c_szObex);
|
|
message.szLocHeader = T2A(szHostNameW);
|
|
message.szAltHeaders = szPort;
|
|
message.szUSN = pszAddr;
|
|
message.szSid = "";
|
|
message.iLifeTime = 1 * 60;
|
|
dwFlags = 0;//SSDP_SERVICE_PERSISTENT;
|
|
|
|
// call the SSDP api
|
|
if ( g_SsdpDLL.LoadFunctionPointers() )
|
|
{
|
|
// init SSDP
|
|
//
|
|
(SSDPSTARTUP) g_SsdpDLL[SSDP_STARTUP]();
|
|
|
|
*SsdpHandle = ((REGISTERSERVICE) g_SsdpDLL[SSDP_REGISTER_SERVICE])(&message, dwFlags);
|
|
|
|
if (SsdpHandle == INVALID_HANDLE_VALUE) {
|
|
|
|
Trace2( "SSDP RegisterService on port 0x%lx failed! 0x%lx\n", dwPort, GetLastError());
|
|
goto Error;
|
|
|
|
} else {
|
|
|
|
Trace3("RegisterWithSsdp - host name %ws, addr %s, port %d\n", szHostNameW, pszAddr, dwPort);
|
|
}
|
|
}
|
|
|
|
*listenSocket = sock;
|
|
|
|
return TRUE;
|
|
|
|
Error:
|
|
closesocket(sock);
|
|
sock = INVALID_SOCKET;
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
VOID
|
|
UnregisterWithSsdp(
|
|
HANDLE SsdpHandle
|
|
)
|
|
|
|
{
|
|
// call the SSDP api
|
|
if ( g_SsdpDLL.LoadFunctionPointers() ) {
|
|
|
|
((DEREGISTERSERVICE) g_SsdpDLL[SSDP_DEREGISTER_SERVICE])(SsdpHandle, 0);
|
|
//
|
|
// shutdown ssdp
|
|
//
|
|
(SSDPCLEANUP) g_SsdpDLL[SSDP_CLEANUP]();
|
|
}
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
typedef struct _SSDP_CONTROL {
|
|
|
|
HANDLE hNotify;
|
|
HWND hWnd;
|
|
UINT Msg;
|
|
|
|
LONG ReferenceCount;
|
|
|
|
BOOL Closing;
|
|
|
|
SOCKET Socket;
|
|
|
|
WSAOVERLAPPED WsOverlapped;
|
|
|
|
|
|
TCHAR HostName[256];
|
|
|
|
CRITICAL_SECTION Lock;
|
|
|
|
} SSDP_CONTROL, *PSSDP_CONTROL;
|
|
|
|
|
|
VOID
|
|
RemoveReferenceOnSsdpControl(
|
|
PSSDP_CONTROL Control
|
|
);
|
|
|
|
|
|
void
|
|
SsdpCallbackHandler(
|
|
SSDP_CALLBACK_TYPE ct,
|
|
CONST SSDP_MESSAGE *pSsdpMessage,
|
|
HANDLE Context
|
|
)
|
|
|
|
{
|
|
|
|
PSSDP_CONTROL Control=(PSSDP_CONTROL)Context;
|
|
|
|
DbgPrint("SsdpCallbackHandler: %d\n",ct);
|
|
|
|
switch (ct) {
|
|
|
|
case SSDP_DONE:
|
|
|
|
case SSDP_ALIVE:
|
|
case SSDP_FOUND:
|
|
case SSDP_EVENT:
|
|
|
|
DbgPrint("SsdpCallabck: Name=%s, Address=%s\n",pSsdpMessage->szLocHeader,pSsdpMessage->szUSN);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
PostMessage(
|
|
Control->hWnd,
|
|
Control->Msg,
|
|
ct,
|
|
NULL
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
LONG
|
|
RefreshSsdp(
|
|
VOID
|
|
)
|
|
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
g_SsdpDLL.LoadFunctionPointers();
|
|
|
|
// init SSDP
|
|
//
|
|
(SSDPSTARTUP) g_SsdpDLL[SSDP_STARTUP]();
|
|
|
|
(CLEANUPCACHE) g_SsdpDLL[SSDP_CLEANUP_CACHE]();
|
|
|
|
HANDLE hSearch;
|
|
|
|
hSearch = ((FINDSERVICES) g_SsdpDLL[SSDP_FIND_SERVICES])(T2A(c_szObex), NULL, TRUE);
|
|
|
|
if (hSearch != INVALID_HANDLE_VALUE) {
|
|
|
|
((FINDSERVICESCLOSE) g_SsdpDLL[SSDP_FIND_SERVICES_CLOSE])(hSearch);
|
|
}
|
|
|
|
// shutdown ssdp
|
|
(SSDPCLEANUP) g_SsdpDLL[SSDP_CLEANUP]();
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
VOID
|
|
SsdpAddressListChangeHandler(
|
|
DWORD Error,
|
|
DWORD BytesTransfered,
|
|
LPWSAOVERLAPPED WsOverlapped,
|
|
DWORD Flags
|
|
)
|
|
|
|
{
|
|
|
|
PSSDP_CONTROL Control=(PSSDP_CONTROL)WsOverlapped->hEvent;
|
|
|
|
RefreshSsdp();
|
|
|
|
PostMessage(
|
|
Control->hWnd,
|
|
Control->Msg,
|
|
-1,
|
|
NULL
|
|
);
|
|
|
|
DeviceChangeWorker(Control);
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DeviceChangeWorker(
|
|
PVOID Context
|
|
)
|
|
|
|
{
|
|
PSSDP_CONTROL Control=(PSSDP_CONTROL)Context;
|
|
int err;
|
|
DWORD BytesReturned;
|
|
|
|
if (!Control->Closing) {
|
|
|
|
ZeroMemory(&Control->WsOverlapped,sizeof(Control->WsOverlapped));
|
|
|
|
Control->WsOverlapped.hEvent=Control;
|
|
|
|
err=WSAIoctl(
|
|
Control->Socket,
|
|
SIO_ADDRESS_LIST_CHANGE,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&BytesReturned,
|
|
&Control->WsOverlapped,
|
|
SsdpAddressListChangeHandler
|
|
);
|
|
|
|
if (err == SOCKET_ERROR) {
|
|
|
|
if (WSAGetLastError() != WSA_IO_PENDING) {
|
|
//
|
|
// the call failed and return value was not pending
|
|
//
|
|
RemoveReferenceOnSsdpControl(Control);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
RemoveReferenceOnSsdpControl(Control);
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
HANDLE
|
|
CreateSsdpDiscoveryObject(
|
|
LPSTR Service,
|
|
HWND hWnd,
|
|
UINT Msg
|
|
)
|
|
|
|
{
|
|
|
|
PSSDP_CONTROL Control;
|
|
ULONG dwSize;
|
|
BOOL bResult;
|
|
|
|
USES_CONVERSION;
|
|
|
|
Control = new SSDP_CONTROL;
|
|
|
|
if (Control == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
InitializeCriticalSection(&Control->Lock);
|
|
|
|
dwSize=sizeof(Control->HostName)/sizeof(TCHAR);
|
|
GetComputerNameEx(ComputerNameDnsFullyQualified, Control->HostName, &dwSize);
|
|
|
|
Control->Closing =FALSE;
|
|
Control->Socket = INVALID_SOCKET;
|
|
Control->ReferenceCount=1;
|
|
Control->hWnd=hWnd;
|
|
Control->Msg=Msg;
|
|
|
|
g_SsdpDLL.LoadFunctionPointers();
|
|
|
|
// init SSDP
|
|
//
|
|
(SSDPSTARTUP) g_SsdpDLL[SSDP_STARTUP]();
|
|
#if 1
|
|
// Tell SSDP to start notifying us of devices
|
|
//
|
|
(CLEANUPCACHE) g_SsdpDLL[SSDP_CLEANUP_CACHE]();
|
|
#endif
|
|
// register for notification as devices come and go
|
|
//
|
|
Control->hNotify = ((REGISTERNOTIFICAION) g_SsdpDLL[SSDP_REGISTER_NOTIFICATION])(
|
|
NOTIFY_ALIVE,
|
|
T2A(c_szObex),
|
|
NULL,
|
|
SsdpCallbackHandler,
|
|
Control
|
|
);
|
|
|
|
if ((Control->hNotify == INVALID_HANDLE_VALUE) || (Control->hNotify == NULL)) {
|
|
|
|
Trace1("CIpTransport::InitiateDiscovery - RegisterNotification failed! %d", GetLastError());
|
|
|
|
goto CleanUp;
|
|
}
|
|
#if 1
|
|
HANDLE hSearch;
|
|
|
|
hSearch = ((FINDSERVICES) g_SsdpDLL[SSDP_FIND_SERVICES])(T2A(c_szObex), NULL, TRUE);
|
|
|
|
if (hSearch != INVALID_HANDLE_VALUE) {
|
|
|
|
((FINDSERVICESCLOSE) g_SsdpDLL[SSDP_FIND_SERVICES_CLOSE])(hSearch);
|
|
}
|
|
#endif
|
|
|
|
// RefreshSsdp();
|
|
|
|
Control->Socket=socket(AF_INET,SOCK_STREAM,0);
|
|
|
|
if (Control->Socket == INVALID_SOCKET) {
|
|
|
|
goto CleanUp;
|
|
}
|
|
|
|
//
|
|
// add one refcount for the workitem
|
|
//
|
|
InterlockedIncrement(&Control->ReferenceCount);
|
|
|
|
bResult=QueueUserWorkItem(
|
|
DeviceChangeWorker,
|
|
Control,
|
|
WT_EXECUTEINIOTHREAD
|
|
);
|
|
|
|
if (bResult) {
|
|
|
|
return Control;
|
|
|
|
} else {
|
|
|
|
RemoveReferenceOnSsdpControl(Control);
|
|
}
|
|
|
|
CleanUp:
|
|
|
|
RemoveReferenceOnSsdpControl(Control);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
RemoveReferenceOnSsdpControl(
|
|
PSSDP_CONTROL Control
|
|
)
|
|
|
|
{
|
|
|
|
LONG CurrentCount;
|
|
|
|
CurrentCount=InterlockedDecrement(&Control->ReferenceCount);
|
|
|
|
if (CurrentCount == 0) {
|
|
//
|
|
// cleanup notifications with SSDP
|
|
//
|
|
if (Control->hNotify != INVALID_HANDLE_VALUE) {
|
|
|
|
((DEREGISTERNOTIFICAION) g_SsdpDLL[SSDP_DEREGISTER_NOTIFICATION])(Control->hNotify);
|
|
}
|
|
|
|
(SSDPCLEANUP) g_SsdpDLL[SSDP_CLEANUP]();
|
|
|
|
DeleteCriticalSection(&Control->Lock);
|
|
|
|
delete Control;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
CloseSsdpDiscoveryObject(
|
|
HANDLE Context
|
|
)
|
|
|
|
{
|
|
|
|
PSSDP_CONTROL Control=(PSSDP_CONTROL)Context;
|
|
|
|
Control->Closing=TRUE;
|
|
|
|
closesocket(Control->Socket);
|
|
|
|
RemoveReferenceOnSsdpControl(Control);
|
|
|
|
}
|
|
|
|
|
|
LONG
|
|
GetSsdpDevices(
|
|
HANDLE Context,
|
|
POBEX_DEVICE_LIST DeviceList,
|
|
ULONG *ListLength
|
|
)
|
|
|
|
{
|
|
|
|
PSSDP_CONTROL Control=(PSSDP_CONTROL)Context;
|
|
|
|
HANDLE hSearch = NULL;
|
|
LPSTR pszTypeURI;
|
|
ULONG BytesAvailible=*ListLength;
|
|
ULONG BytesUsed=0;
|
|
POBEX_DEVICE CurrentDevice=&DeviceList->DeviceList[0];
|
|
|
|
|
|
USES_CONVERSION;
|
|
|
|
ZeroMemory(DeviceList,BytesAvailible);
|
|
|
|
if (BytesAvailible < FIELD_OFFSET(OBEX_DEVICE_LIST,DeviceList)) {
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
BytesUsed+=FIELD_OFFSET(OBEX_DEVICE_LIST,DeviceList);
|
|
|
|
|
|
DeviceList->DeviceCount=0;
|
|
|
|
pszTypeURI = T2A(c_szObex);
|
|
|
|
hSearch = ((FINDSERVICES) g_SsdpDLL[SSDP_FIND_SERVICES])(pszTypeURI, NULL, FALSE);
|
|
|
|
if (hSearch != INVALID_HANDLE_VALUE) {
|
|
|
|
SSDP_MESSAGE * pSsdpMessage = NULL;
|
|
|
|
BOOL fContinue = ((GETFIRSTSERVICE) g_SsdpDLL[SSDP_GET_FIRST_SERVICE])(hSearch, &pSsdpMessage);
|
|
|
|
ASSERT(DeviceList->DeviceCount == 0);
|
|
|
|
while (fContinue) {
|
|
|
|
ULONG Address = inet_addr(pSsdpMessage->szUSN);
|
|
int Port = atoi(pSsdpMessage->szAltHeaders);
|
|
|
|
if (BytesAvailible >= BytesUsed + sizeof(OBEX_DEVICE)) {
|
|
//
|
|
// we have enough romm in the buffer for this one
|
|
//
|
|
MultiByteToWideChar(
|
|
CP_ACP,
|
|
0,
|
|
pSsdpMessage->szLocHeader,
|
|
-1,
|
|
CurrentDevice->DeviceName,
|
|
sizeof(CurrentDevice->DeviceName)/sizeof(WCHAR)
|
|
);
|
|
|
|
DbgPrint("irmon: count=%d, remote=%ws, host=%ws\n",DeviceList->DeviceCount,CurrentDevice->DeviceName,Control->HostName);
|
|
|
|
if (lstrcmpi(CurrentDevice->DeviceName,Control->HostName) != 0) {
|
|
//
|
|
// not this machine
|
|
//
|
|
CurrentDevice->DeviceType=TYPE_IP;
|
|
|
|
CurrentDevice->DeviceName[sizeof(CurrentDevice->DeviceName)/sizeof(WCHAR)]=L'\0';
|
|
|
|
CurrentDevice->DeviceSpecific.s.Ip.IpAddress=Address;
|
|
|
|
CurrentDevice->DeviceSpecific.s.Ip.Port=(USHORT)Port;
|
|
|
|
CurrentDevice++;
|
|
|
|
DeviceList->DeviceCount++;
|
|
}
|
|
|
|
}
|
|
|
|
BytesUsed+=sizeof(OBEX_DEVICE);
|
|
|
|
fContinue = ((GETNEXTSERVICE) g_SsdpDLL[SSDP_GET_NEXT_SERVICE])(hSearch, &pSsdpMessage);
|
|
}
|
|
|
|
((FINDSERVICESCLOSE) g_SsdpDLL[SSDP_FIND_SERVICES_CLOSE])(hSearch);
|
|
|
|
if (BytesUsed > BytesAvailible) {
|
|
|
|
*ListLength=BytesUsed;
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
DbgPrint("irmon: %d ip device found\n",DeviceList->DeviceCount);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
} else {
|
|
//
|
|
// Check to see if the handle is invalid merely because no devices
|
|
// are present
|
|
//
|
|
DWORD dwError = GetLastError();
|
|
|
|
if (dwError == ERROR_NO_MORE_SERVICES) {
|
|
|
|
Trace0("FindServices failed because no devices were present. This is OK");
|
|
dwError=ERROR_SUCCESS;
|
|
|
|
} else {
|
|
|
|
Trace1("FindServices call failed in FindByDeviceType %lx", dwError);
|
|
}
|
|
return dwError;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif //IP_OBEX
|