/* File netnum.cpp Private helper functions for setting the internal network number. We talk to ndis directly to set this number. Paul Mayfield, 1/5/98 */ #include #include #include #include #include #include extern "C" { DWORD OutputDebugger (LPSTR pszError, ...); }; //$ REVIEW - Start - This is moving to private\inc\ipxpnp.h #define IPX_RECONFIG_VERSION 0x1 #define RECONFIG_AUTO_DETECT 1 #define RECONFIG_MANUAL 2 #define RECONFIG_PREFERENCE_1 3 #define RECONFIG_NETWORK_NUMBER_1 4 #define RECONFIG_PREFERENCE_2 5 #define RECONFIG_NETWORK_NUMBER_2 6 #define RECONFIG_PREFERENCE_3 7 #define RECONFIG_NETWORK_NUMBER_3 8 #define RECONFIG_PREFERENCE_4 9 #define RECONFIG_NETWORK_NUMBER_4 10 #define RECONFIG_PARAMETERS 10 // // Main configuration structure. // typedef struct _RECONFIG { unsigned long ulVersion; BOOLEAN InternalNetworkNumber; BOOLEAN AdapterParameters[RECONFIG_PARAMETERS]; } RECONFIG, *PRECONFIG; //$ REVIEW - End - This is moving to private\inc\ipxpnp.h static const TCHAR c_szIpx[] = TEXT("nwlnkipx"); static const TCHAR c_szEmpty[] = TEXT(""); static const TCHAR c_szVirtualNetworkNumber[] = TEXT("VirtualNetworkNumber"); static const TCHAR c_szIpxParameters[] = TEXT("System\\CurrentControlSet\\Services\\NwlnkIpx\\Parameters"); static const TCHAR c_szDevice[] = TEXT("\\Device\\"); ULONG CchMsz ( LPCTSTR pmsz) { ULONG cchTotal = 0; ULONG cch; // NULL strings have zero length by definition. if (!pmsz) return 0; while (*pmsz) { cch = lstrlen (pmsz) + 1; cchTotal += cch; pmsz += cch; } // Return the count of characters so far plus room for the // extra null terminator. return cchTotal + 1; } void SetUnicodeMultiString ( IN OUT UNICODE_STRING* pustr, IN LPCWSTR pmsz ) { //AssertSz( pustr != NULL, "Invalid Argument" ); //AssertSz( pmsz != NULL, "Invalid Argument" ); pustr->Buffer = const_cast(pmsz); pustr->Length = (USHORT) (CchMsz(pustr->Buffer) * sizeof(WCHAR)); pustr->MaximumLength = pustr->Length; } void SetUnicodeString ( IN OUT UNICODE_STRING* pustr, IN LPCWSTR psz ) { //AssertSz( pustr != NULL, "Invalid Argument" ); //AssertSz( psz != NULL, "Invalid Argument" ); pustr->Buffer = const_cast(psz); pustr->Length = (USHORT)(lstrlenW(pustr->Buffer) * sizeof(WCHAR)); pustr->MaximumLength = pustr->Length + sizeof(WCHAR); } HRESULT HrSendNdisHandlePnpEvent ( UINT uiLayer, UINT uiOperation, LPCWSTR pszUpper, LPCWSTR pszLower, LPCWSTR pmszBindList, PVOID pvData, DWORD dwSizeData) { UNICODE_STRING umstrBindList; UNICODE_STRING ustrLower; UNICODE_STRING ustrUpper; UINT nRet; HRESULT hr = S_OK; //Assert(NULL != pszUpper); //Assert((NDIS == uiLayer)||(TDI == uiLayer)); //Assert( (BIND == uiOperation) || (RECONFIGURE == uiOperation) || (UNBIND == uiOperation) ); //AssertSz( FImplies( ((NULL != pmszBindList) && (0 != lstrlenW( pmszBindList ))), // (RECONFIGURE == uiOperation) && // (TDI == uiLayer) && // (0 == lstrlenW( pszLower ))), // "bind order change requires a bind list, no lower, only for TDI, and with Reconfig for the operation" ); // optional strings must be sent as empty strings // if (NULL == pszLower) { pszLower = c_szEmpty; } if (NULL == pmszBindList) { pmszBindList = c_szEmpty; } // build UNICDOE_STRINGs SetUnicodeMultiString( &umstrBindList, pmszBindList ); SetUnicodeString( &ustrUpper, pszUpper ); SetUnicodeString( &ustrLower, pszLower ); // Now submit the notification nRet = NdisHandlePnPEvent( uiLayer, uiOperation, &ustrLower, &ustrUpper, &umstrBindList, (PVOID)pvData, dwSizeData ); if (!nRet) { //hr = HrFromLastWin32Error(); hr = GetLastError(); } return( hr ); } HRESULT HrSendNdisPnpReconfig ( UINT uiLayer, LPCWSTR wszUpper, LPCWSTR wszLower, PVOID pvData, DWORD dwSizeData) { //Assert(NULL != wszUpper); //Assert((NDIS == uiLayer)||(TDI == uiLayer)); //tstring strLower; WCHAR strLower[512]; BOOL bSendNull = FALSE; if (NULL == wszLower) { wszLower = c_szEmpty; } // If a lower component is specified, prefix with "\Device\" else // strLower's default of an empty string will be used. if ( wszLower && lstrlenW(wszLower)) { //strLower = c_szDevice; //strLower += wszLower; wcscpy(strLower, c_szDevice); wcscat(strLower, wszLower); } else bSendNull = TRUE; HRESULT hr = HrSendNdisHandlePnpEvent(uiLayer, RECONFIGURE, wszUpper, //strLower.c_str(), (bSendNull) ? NULL : strLower, c_szEmpty, pvData, dwSizeData); OutputDebugger( "HrSendNdisHandlePnpEvent: %x\n", hr); return hr; } HRESULT HrSetIpxVirtualNetNum(DWORD dwValue) { RECONFIG Config; HKEY hkey; HRESULT hr; // Open the registry key LONG lr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szIpxParameters, 0, KEY_ALL_ACCESS, &hkey); hr = HRESULT_FROM_WIN32(lr); if (SUCCEEDED(hr)) { // Splat the data lr = RegSetValueEx(hkey, c_szVirtualNetworkNumber, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD)); hr = HRESULT_FROM_WIN32(lr); if (SUCCEEDED(hr)) { memset(&Config, 0, sizeof(RECONFIG)); Config.ulVersion = IPX_RECONFIG_VERSION; Config.InternalNetworkNumber = TRUE; // Workstation or server? // Paul, Normally I only send this notification for servers. I // Assume you'll be able to distinguish // Now submit the global reconfig notification hr = HrSendNdisPnpReconfig(NDIS, c_szIpx, c_szEmpty, &Config, sizeof(RECONFIG)); } RegCloseKey(hkey); } return hr; } // Here's the function we want -- it sets the ipx internal network number // programatically. EXTERN_C DWORD SetIpxInternalNetNumber(DWORD dwNetNum) { return HrSetIpxVirtualNetNum(dwNetNum); }