//+------------------------------------------------------------------- // // File: endpnt.cxx // // Contents: class for managing endpoint structures. both the local // and remote service object instances use this class. // // local service object uses RegisterAllProtseqs to register // all available protocol sequences with Rpc, and to accquire // the list of full string bingings. // // the remote service object uses it to select, from amongst // the many string bindings, the most preffered, to bind to. // // Classes: CEndPoint // // Functions: GoodSEp // // History: 23-Nov-92 Rickhi Created // 31-Dec-93 ErikGav Chicago port // 28-Jun-94 BruceMa Memory sift fixes // 03-Mar-95 JohannP Delaying rpc initialize // //-------------------------------------------------------------------- #include #include // class definition #include // CComputerName extern CComputerName g_CompName; // static class data members ULONG CEndPoint::s_ulLocalBindingCount = 0; WCHAR CEndPoint::s_wszLocalProtseq[MAX_BINDINGS][MAX_PROTSEQ_STRLEN]; WCHAR CEndPoint::s_wszLocalNetworkAddr[MAX_BINDINGS][MAX_NETWORKADDR_STRLEN]; #ifdef _CAIRO_ // // [richardw] -- See comment down in CEndPoint::RegisterProtseq // SECURITY_DESCRIPTOR TemporarySecurityDescriptor; BOOL fTempSDInitialized = FALSE; #endif #ifdef _CHICAGO_ ULONG GetOleNotificationWnd(); #else #define GetOleNotificationWnd() 0 #endif // _CHICAGO_ // this is here to help debug some heap corruption problems. #if DBG==1 void MyRpcStringFree(LPWSTR *ppwszString) { CairoleDebugOut((DEB_ENDPNT, "CEndPoint::RpcStringFree %x %ws\n", *ppwszString, *ppwszString)); if (*ppwszString) { RpcStringFree(ppwszString); } } #else #define MyRpcStringFree(x) RpcStringFree(x) //#define ValidateStringBinding(x) #endif // DBG==1 // attempts to validate the string binding void ValidateStringBinding(LPWSTR pwszSB) { LPWSTR pwszProtseq = NULL; LPWSTR pwszNetworkAddr = NULL; RPC_STATUS sc = RpcStringBindingParse(pwszSB, NULL, &pwszProtseq, &pwszNetworkAddr, NULL, NULL); if (RPC_S_OK == sc) { // verify the protseq is reasonable sc = RpcNetworkIsProtseqValid(pwszProtseq); if (RPC_S_OK != sc) { CairoleDebugOut((DEB_ERROR, "Invalid protseq sc:%x pwsz:%ws pwsz:%ws\n", sc, pwszProtseq, pwszSB)); } MyRpcStringFree(&pwszProtseq); MyRpcStringFree(&pwszNetworkAddr); } else { CairoleDebugOut((DEB_ERROR, "RpcStringBindingParse failed:sc:%x pwsz:%ws\n", sc, pwszSB)); } } inline WCHAR * WideStringCopy(WCHAR *pwz) { ULONG cbStr; WCHAR *pStr; pStr = (WCHAR *)PrivMemAlloc(cbStr=((lstrlenW(pwz)+1)*sizeof(WCHAR))); if (pStr != NULL) { memcpy(pStr,pwz,cbStr); } return(pStr); } //+------------------------------------------------------------------- // // Member: CEndPoint::SelectStringBinding // // Purpose: selects a stringbinding from the array of string bindings. // sets up _pwszPrefStringBinding, _pwszPrefProtseq, and // _eNetworkAddr with copies of the strings. // // Algorithm: if we can, choose lrpc, else try tcp, else whatever is // first in the list. // // History: 08-Sep-93 Rickhi Created // //-------------------------------------------------------------------- void CEndPoint::SelectStringBinding(void) { TRACECALL(TRACE_INITIALIZE, "SelectStringBinding"); CairoleDebugOut((DEB_ENDPNT, "CEndPoint::SelectStringBinding Enter \n")); Win4Assert(_pSEp && "Illformed CEndPoint Object"); #ifdef _CHICAGO_ if( _pSEp && _pSEp->ulStrLen != 0) { LPWSTR pwszStringBinding = _pSEp->awszEndPoint; // there is a valid endpoint // just copy the endpoint string to if (_pwszPrefStringBinding) { PrivMemFree(_pwszPrefStringBinding); } _pwszPrefStringBinding = WideStringCopy(pwszStringBinding); if (_pwszPrefProtseq) { PrivMemFree(_pwszPrefProtseq); // free old one } _pwszPrefProtseq = (LPWSTR)PrivMemAlloc(32); if (_pwszPrefProtseq ) { memcpy(_pwszPrefProtseq,LOCAL_PROTSEQ,sizeof(LOCAL_PROTSEQ)); } _eNetworkAddr = NA_SAME_MACHINE; } else { // no valid endpoint if (_pwszPrefStringBinding == NULL) { CairoleDebugOut((DEB_ENDPNT, "CEndPoint::SelectStringBinding Generating fake StringBinding\n")); _pwszPrefStringBinding = (LPWSTR)PrivMemAlloc(128); if (_pwszPrefStringBinding) { wsprintf(_pwszPrefStringBinding, L"%ws:%ws[OLE%-08.8X]", LOCAL_PROTSEQ,g_CompName.GetComputerName(),CoGetCurrentProcess()); } } if(_pwszPrefProtseq == NULL) { _pwszPrefProtseq = (LPWSTR)PrivMemAlloc(64); if (_pwszPrefProtseq ) { memcpy(_pwszPrefProtseq,LOCAL_PROTSEQ,sizeof(LOCAL_PROTSEQ)); } } _eNetworkAddr = NA_SAME_MACHINE; CairoleDebugOut((DEB_ENDPNT, " PrefStringBinding: %ws\n", _pwszPrefStringBinding)); CairoleDebugOut((DEB_ENDPNT, " PrefProtseq: %ws\n", _pwszPrefProtseq)); } #else // examine each Rpc string binding to ensure we can support it. // we also scan to see if we can use our favourite protocol sequence // as it is assumed to be the fastest one. LPWSTR pwszStringBinding = _pSEp->awszEndPoint; LPWSTR pwszLastStringBinding = pwszStringBinding + _pSEp->ulStrLen; BOOL fDone = FALSE; while (!fDone && pwszStringBinding < pwszLastStringBinding) { LPWSTR pwszProtseq = NULL; LPWSTR pwszNetworkAddr = NULL; CairoleDebugOut((DEB_ENDPNT, "RpcStringBindParse: wszStringBind: %ws \n", pwszStringBinding)); if (S_OK == RpcStringBindingParse(pwszStringBinding, NULL, &pwszProtseq, &pwszNetworkAddr, NULL, NULL)) { CairoleDebugOut((DEB_ENDPNT, "RpcStringBindParse: pwszProtseq=%x pwszNetWorkAddr=%x\n", pwszProtseq, pwszNetworkAddr)); CairoleDebugOut((DEB_ENDPNT, "RpcStringBindParse: pwszProtseq=%ws pwszNetWorkAddr=%ws\n", pwszProtseq, pwszNetworkAddr)); // is this protocol sequence supported on our machine? if (RpcNetworkIsProtseqValid(pwszProtseq) == S_OK) { if (!lstrcmpW(pwszProtseq, LOCAL_PROTSEQ)) { #ifdef _CHICAGO_ // // BUGBUG: Chico registry broken // RPC broken too // Avalanche of BUGBUG's ends here // // THE HACK STOPS HERE // --Erik & Alex & Rick & Dave // if (1) #else if (!lstrcmpW(pwszNetworkAddr, g_CompName.GetComputerName())) #endif { if (_pwszPrefStringBinding) { PrivMemFree(_pwszPrefStringBinding); } _pwszPrefStringBinding = WideStringCopy(pwszStringBinding); if (_pwszPrefProtseq) MyRpcStringFree(&_pwszPrefProtseq); // free old one _pwszPrefProtseq = pwszProtseq; _eNetworkAddr = NA_SAME_MACHINE; fDone = TRUE; } else { _eNetworkAddr = NA_DIFF_MACHINE; MyRpcStringFree(&pwszProtseq); // free it } } #ifdef _CAIRO_ else { // CODEWORK: if we assume that there is always lrpc // available, then we can delete the following code for // setting the _eNetworkAddr and just loop until we hit // that protseq above. if (_eNetworkAddr == NA_DONT_KNOW) { // first, set _eNetworkAddr correctly. Find the local // protseq that matches this protseq and then compare // the corresponding network addresses. for (ULONG i=0; iawszEndPoint)); } } else if (!_pSEp) { rc = UpdateSEP( pwszEndPoint ); } CairoleDebugOut((DEB_ENDPNT,"CEndPoint::RegisterProtseq done rc=%x\n", rc)); return rc; } #ifdef _CHICAGO_ //+--------------------------------------------------------------------------- // // Method: CEndPoint::RemoveDefaultProtseq // // Synopsis: Removes an endpoint; on Win95 endpoints are per thread // // Arguments: [void] -- // // Returns: // // History: 3-15-95 JohannP (Johann Posch) Created // // Notes: // //---------------------------------------------------------------------------- HRESULT CEndPoint::RemoveDefaultProtseq(void) { CairoleDebugOut((DEB_ENDPNT,"CEndPoint::RemoveDefaultProtseq\n")); HRESULT rc = S_OK; WCHAR *pwszProtseq = LOCAL_PROTSEQ; WCHAR pwszEndPoint[12]; pwszEndPoint[0] = 0; { // Create the same endpoint string wsprintf(pwszEndPoint, L"OLE%-08.8X", CoGetCurrentProcess()); // remove the endpoint rc = I_RpcServerUnregisterEndpointW(pwszProtseq, pwszEndPoint); } CairoleDebugOut((DEB_ENDPNT,"CEndPoint::RemoveDefaultProtseq Seq:%ws endpoint:%ws\n", pwszProtseq, pwszEndPoint)); return rc; } #endif // _CHICAGO_ #ifndef _CHICAGO_ //+------------------------------------------------------------------- // // Member: CEndPoint::UpdateSEP // // Purpose: updates the SEP structure with the current list of // endpoints. This is called after registering a new // protocol sequence, so that subsequently marshalled // interfaces will contain the new endpoint. // // History: 23-Nov-92 Rickhi Created // // Note: it is very important that the order of string bindings // in the SEp does not change after registering a new // protocol sequence, otherwise clients would start creating // two different service objects. currently this is valid // because Rpc returns the handles in the binding vector in // the same order. // //-------------------------------------------------------------------- HRESULT CEndPoint::UpdateSEP( LPWSTR unused ) { TRACECALL(TRACE_INITIALIZE, "UpdateSEP"); CairoleDebugOut((DEB_ENDPNT, "CEndPoint::UpdateSEP Enter\n")); // inquire all binding handles. there is one per registered // protocol sequence. RPC_BINDING_VECTOR *pBindVect = NULL; RPC_STATUS rc = RpcServerInqBindings(&pBindVect); if (rc == S_OK) { LPWSTR pwszFullStringBinding[MAX_BINDINGS]; ULONG ulStrLen[MAX_BINDINGS]; ULONG ulTotalStrLen = 0; // total string lengths ULONG j = 0; // BindString we're using // CODEWORK: this just prevents a GP if the max is exceeded. should // revisit for Cairo and keep only the string bindings in which the // protseqs are unique...thus keeping the marshalled data sizes small. if (pBindVect->Count > MAX_BINDINGS) { CairoleDebugOut((DEB_WARN, "Excessive BindingHandle count\n")); pBindVect->Count = MAX_BINDINGS; } // iterate over the handles to get the string bindings // and dynamic endpoints for all available protocols. for (ULONG i=0; iCount; i++) { LPWSTR pwszStringBinding = NULL; pwszFullStringBinding[j] = NULL; ulStrLen[j] = 0; rc = RpcBindingToStringBinding(pBindVect->BindingH[i], &pwszStringBinding); Win4Assert(rc == S_OK && "RpcBindingToStringBinding"); if (rc == S_OK) { CairoleDebugOut((DEB_ENDPNT, "pwszStringBinding=%x\n", pwszStringBinding)); LPWSTR pwszEndPoint = NULL; LPWSTR pwszObjectUUID = NULL; LPWSTR pwszProtseq = NULL; LPWSTR pwszNetworkAddr = NULL; // parse the string binding, then recompose with the // endpoint added on, and store it in the array rc = RpcStringBindingParse(pwszStringBinding, &pwszObjectUUID, &pwszProtseq, &pwszNetworkAddr, &pwszEndPoint, NULL); Win4Assert(rc == S_OK && "RpcStringBindingParse"); if (rc == S_OK) { CairoleDebugOut((DEB_ENDPNT, "pwszObjectUUID=%x\n", pwszObjectUUID)); CairoleDebugOut((DEB_ENDPNT, "pwszProtseq=%x\n", pwszProtseq)); CairoleDebugOut((DEB_ENDPNT, "pwszNetworkAddr=%x\n", pwszNetworkAddr)); CairoleDebugOut((DEB_ENDPNT, "pwszEndPoint=%x\n", pwszEndPoint)); pwszFullStringBinding[j] = pwszStringBinding; // record the string lengths for later. include room // for the NULL terminator. ulStrLen[j] = lstrlenW(pwszFullStringBinding[j])+1; ulTotalStrLen += ulStrLen[j]; // store the protseq & network addr stings // in the static variables Win4Assert(lstrlenW(pwszProtseq) < MAX_PROTSEQ_STRLEN); Win4Assert(lstrlenW(pwszNetworkAddr) < MAX_NETWORKADDR_STRLEN); lstrcpyW(&s_wszLocalProtseq[j][0], pwszProtseq); lstrcpyW(&s_wszLocalNetworkAddr[j][0], pwszNetworkAddr); j++; // free the intermediate strings MyRpcStringFree(&pwszObjectUUID); MyRpcStringFree(&pwszProtseq); MyRpcStringFree(&pwszNetworkAddr); MyRpcStringFree(&pwszEndPoint); } } } // for s_ulLocalBindingCount = j; // now that all the string bindings and endpoints have been // accquired, allocate an SEndPoint large enough to hold them // all and copy them into the structure. if (ulTotalStrLen > 0) { SEndPoint *pSEp = (SEndPoint *) PrivMemAlloc(NEWSEPSIZE(ulTotalStrLen)); if (pSEp) { pSEp->ulStrLen = ulTotalStrLen; // copy in the strings LPWSTR pwszNext = pSEp->awszEndPoint; for (i=0; iCount; i++) { rc = RpcBindingToStringBinding(pBindVect->BindingH[i], &pwszStringBinding); Win4Assert(rc == S_OK && "RpcBindingToStringBinding"); if (rc == S_OK) { CairoleDebugOut((DEB_ITRACE, "pwszStringBinding=%x\n", pwszStringBinding)); // parse the string binding rc = RpcStringBindingParse(pwszStringBinding, NULL, NULL, NULL, &pwszEndPoint, NULL); Win4Assert(rc == S_OK && "RpcStringBindingParse"); if (rc == S_OK) { CairoleDebugOut((DEB_ITRACE, "pwszEndPoint=%ws\n", pwszEndPoint)); fFound = lstrcmpW( pwszEndPoint, pwszDesiredEndPoint ) == 0; // free the intermediate strings MyRpcStringFree(&pwszEndPoint); if (fFound) { ulStrLen = lstrlenW( pwszStringBinding ) + 1; SEndPoint *pSEp = (SEndPoint *) PrivMemAlloc(NEWSEPSIZE(ulStrLen)); if (pSEp) { pSEp->ulStrLen = ulStrLen; lstrcpyW(pSEp->awszEndPoint, pwszStringBinding); MyRpcStringFree(&pwszStringBinding); if (pSEp->ulStrLen == 0) { // no binding strings. this is an error. CairoleDebugOut((DEB_ERROR,"No Rpc ProtSeq/EndPoints Generated\n")); rc = E_FAIL; break; } else { PrivMemFree(_pSEp); #ifdef _CHICAGO_ pSEp->ulhwnd = 0; #endif _pSEp = pSEp; break; } } } } MyRpcStringFree(&pwszStringBinding); } } // for // free the binding vector RpcBindingVectorFree(&pBindVect); } #if DBG==1 // display our binding strings on the debugger DisplayAllStringBindings(); #endif CairoleDebugOut((DEB_ITRACE | DEB_ENDPNT,"CEndPoint::UpdateSEP Exit rc=%x\n", rc)); return rc; } #endif //+------------------------------------------------------------------- // // Member: CEndPoint::CEndPoint, public // // Synopsis: constructor for endpoint object. this simply stores // a pointer to the SEndPoint structure. // // History: 23-Nov-93 Rickhi Created // //-------------------------------------------------------------------- CEndPoint::CEndPoint(SEndPoint *pSEp, HRESULT &hr, BOOL fCopy) : _fCopy(fCopy), _pwszPrefStringBinding(NULL), _pwszPrefProtseq(NULL), _fRegActiveProtseq(FALSE), _eNetworkAddr(NA_DONT_KNOW) { hr = S_OK; // assume success CairoleDebugOut((DEB_ENDPNT, "CEndPoint::CEndPoint ctor fCopy:%d; pSEp:%x\n", fCopy, _pSEp)); _fFakeInit = FALSE; if (_fCopy && pSEp) { _pSEp = (SEndPoint *) PrivMemAlloc(SEPSIZE(pSEp)); if (_pSEp) { memcpy(_pSEp, pSEp, COPYSEPSIZE(pSEp)); } else { hr = E_OUTOFMEMORY; } } else { _pSEp = pSEp; } CairoleDebugOut((DEB_ENDPNT, "CEndPoint::CEndPoint %x _pSEp=%x\n", this, _pSEp)); } //+------------------------------------------------------------------- // // Member: CEndPoint::~CEndPoint, public // // Synopsis: destructor for the endpoint object. this deletes the // pointer to the SEndPoint structure only if a copy was // made. // // History: 23-Nov-93 Rickhi Created // //-------------------------------------------------------------------- CEndPoint::~CEndPoint(void) { CairoleDebugOut((DEB_ENDPNT, "CEndPoint::~CEndPoint _pSEp=%x\n", _pSEp)); if (_fFakeInit) { PrivMemFree(_pSEp); PrivMemFree(_pwszPrefStringBinding); PrivMemFree(_pwszPrefProtseq); } else { if (_fCopy) { PrivMemFree(_pSEp); } PrivMemFree(_pwszPrefStringBinding); if (_pwszPrefProtseq) { #ifdef _CHICAGO_ PrivMemFree(_pwszPrefProtseq); #else MyRpcStringFree(&_pwszPrefProtseq); #endif } } } #ifdef _CHICAGO_ //+--------------------------------------------------------------------------- // // Method: CEndPoint::CreateFakeSEp // // Synopsis: creates a fake endpoint structur on Win95 // the endpoint // // Arguments: [void] -- // // Returns: // // History: 3-17-95 JohannP (Johann Posch) Created // // Notes: // //---------------------------------------------------------------------------- SCODE CEndPoint::CreateFakeSEp(void) { CairoleDebugOut((DEB_ENDPNT, "CEndPoint::CreateFakeSEp _pSEp=%x\n", _pSEp)); SCODE sc = RPC_S_OK; if(!GetSEp() || GetStrLen() == 0) { // create a fake endpoint ULONG ulStrLen = 0; // string length WCHAR pwszStringBinding[128]; pwszStringBinding[0] = 0; wsprintf(pwszStringBinding, L"%ws:%ws[OLE%-08.8X]", LOCAL_PROTSEQ,g_CompName.GetComputerName(),CoGetCurrentProcess()); ulStrLen = lstrlenW( pwszStringBinding ) + 1; SEndPoint *pSEp = (SEndPoint *) PrivMemAlloc(NEWSEPSIZE(ulStrLen)); if (pSEp) { pSEp->ulStrLen = ulStrLen; lstrcpyW(pSEp->awszEndPoint, pwszStringBinding); if (pSEp->ulStrLen == 0) { // no binding strings. this is an error. CairoleDebugOut((DEB_ERROR,"No Rpc ProtSeq/EndPoints Generated\n")); sc = E_FAIL; } else { CairoleDebugOut((DEB_ENDPNT, "CEndPoint::CreateFakeSEp New pSEp=%x \n", pSEp)); #ifdef _CHICAGO_ pSEp->ulhwnd = GetOleNotificationWnd(); #endif SetNewSEp(pSEp); _fFakeInit = TRUE; } } } CairoleDebugOut((DEB_ENDPNT, "CEndPoint::CreateFakeSEp _pSEp=%x done\n", _pSEp)); return sc; } //+--------------------------------------------------------------------------- // // Method: CEndPoint::SetNewSEp // // Synopsis: // // Arguments: [pSEp] -- // // Returns: // // History: 3-24-95 JohannP (Johann Posch) Created // // Notes: // //---------------------------------------------------------------------------- SCODE CEndPoint::SetNewSEp(SEndPoint *pSEp) { Win4Assert(pSEp); CairoleDebugOut((DEB_ENDPNT, "CEndPoint::SetNewSEp _pSEp=%x pSEp=%x\n", _pSEp, pSEp)); SCODE sc = E_OUTOFMEMORY; if (pSEp) { CairoleDebugOut((DEB_ENDPNT, "CEndPoint::SetNewSEp pSEp->awsEndPoint=%ws\n", pSEp->awszEndPoint)); // if the old _pSEp was a copy, free it PrivMemFree(_pSEp); // point at the new one _pSEp = pSEp; sc = S_OK; } CairoleDebugOut((DEB_ENDPNT, "CEndPoint::SetNewSEp done rc=%x\n", sc)); return sc; } #endif // _CHICAGO_ //+------------------------------------------------------------------- // // Member: CEndPoint::Replace, public // // Synopsis: replaces the SEndPoint with a new one. // called from RpcService::RegisterProtseq after getting // a new SEp from the remote machine while marshalling a // proxy. // // History: 23-Nov-93 Rickhi Created // //-------------------------------------------------------------------- SCODE CEndPoint::Replace(SEndPoint *pSEp) { CairoleDebugOut((DEB_ENDPNT, "CEndPoint::Replace _pSEp=%x pSEp=%x\n", _pSEp, pSEp)); Win4Assert(pSEp); // allocate a new pSEp SEndPoint *pSEpTmp = (SEndPoint *) PrivMemAlloc(SEPSIZE(pSEp)); if (pSEpTmp) { // copy in the data memcpy(pSEpTmp, pSEp, COPYSEPSIZE(pSEp)); // if the old _pSEp was a copy, free it if (_fCopy) PrivMemFree(_pSEp); // point at the new one _pSEp = pSEpTmp; _fCopy = TRUE; // we now need to reselect our favourite string binding, since // _pwszPrefStringBinding points into the array in pSEp. SelectStringBinding(); return (_pwszPrefStringBinding) ? S_OK : E_OUTOFMEMORY; } else { return E_OUTOFMEMORY; } } //+------------------------------------------------------------------- // // Member: CEndPoint::IsEqual, public // // Synopsis: compares two SEndPoint structures and returns TRUE if // they are equal. // // History: 23-Nov-93 Rickhi Created // // Note: just compare the first string in each structure. if // they are equal, then they refer to the same process. // //-------------------------------------------------------------------- BOOL CEndPoint::IsEqual(SEndPoint *pSEp) { if (pSEp == _pSEp) return TRUE; // ptrs are same, -> equal if (!pSEp || !_pSEp) return FALSE; // only one of them is NULL, -> not equal return !(lstrcmpW(pSEp->awszEndPoint, _pSEp->awszEndPoint)); } //+------------------------------------------------------------------- // // Member: CEndPoint::CopySEp, public // // Synopsis: returns a pointer to a new copy of the SEndPoint structure. // or NULL if out of memory // // History: 23-Nov-93 Rickhi Created // //-------------------------------------------------------------------- SEndPoint *CEndPoint::CopySEp(void) { Win4Assert(_pSEp && "Illformed CEndPoint object"); SEndPoint *pSEp = (SEndPoint *) PrivMemAlloc(GetSEpSize()); if (pSEp) { memcpy(pSEp, _pSEp, COPYSEPSIZE(_pSEp)); } CairoleDebugOut((DEB_ENDPNT, "CEndPoint::CopySEP pSEp=%x %ws\n", pSEp, pSEp)); return pSEp; } #if DBG==1 //+------------------------------------------------------------------- // // Member: CEndPoint::DisplayAllStringBindings, public // // Synopsis: prints the stringbindings to the debugger // // History: 23-Nov-93 Rickhi Created // //-------------------------------------------------------------------- void CEndPoint::DisplayAllStringBindings(void) { if (_pSEp) { LPWSTR pwszNext = _pSEp->awszEndPoint; LPWSTR pwszEnd = pwszNext + _pSEp->ulStrLen; while (pwszNext < pwszEnd) { CairoleDebugOut((DEB_ENDPNT, "pSEp=%x %ws\n", pwszNext, pwszNext)); pwszNext += lstrlenW(pwszNext) + 1; } } } //+------------------------------------------------------------------- // // Function: GoodSEp, public // // Synopsis: validates that the given SEP is OK. // // History: 23-Nov-93 AlexMit Created // //-------------------------------------------------------------------- BOOL GoodSEp(SEndPoint *pSEp) { Win4Assert(pSEp); ULONG ulLen = pSEp->ulStrLen; ULONG i = 0; while (i < ulLen && ((pSEp->awszEndPoint[i] & 0xff) != 0xbd) && ((pSEp->awszEndPoint[i] & 0xff00) != 0xbd00)) i++; return i == ulLen; } #endif // DBG