|
|
/*++
Copyright (c) 1997 FORE Systems, Inc. Copyright (c) 1997 Microsoft Corporation
Module Name:
aas.c
Abstract:
ATM ARP Admin Utility.
Usage:
atmarp
Revision History:
Who When What -------- -------- --------------------------------------------- josephj 06-10-1998 Created (adapted from atmlane admin utility).
Notes:
Modelled after atmlane utility.
--*/
#include "common.h"
#include "..\atmarps\arp.h"
#include "..\atmarps\ioctl.h"
#include "atmmsg.h"
//
// Globals
//
static CHAR DefaultDeviceName[] = "\\\\.\\AtmArpServer"; static CHAR *pDeviceName = DefaultDeviceName;
//
// LoadMessages - courtesy IPCONFIG
//
// Loads all internationalizable messages into the various tables
//
VOID LoadMessages( ) { }
BOOL CheckVersion( HANDLE DeviceHandle ) { return TRUE; }
BOOL AasGetInterfaces( HANDLE DeviceHandle, PINTERFACES pInterfaces, ULONG cbInterfaces ) { ULONG BytesReturned; BOOL Result = FALSE;
if (DeviceIoControl( DeviceHandle, ARPS_IOCTL_QUERY_INTERFACES, (PVOID)pInterfaces, cbInterfaces, (PVOID)pInterfaces, cbInterfaces, &BytesReturned, 0)) { UINT u = pInterfaces->NumberOfInterfaces; //
// Fixup pointers
//
for (u=0;u<pInterfaces->NumberOfInterfaces;u++) { INTERFACE_NAME *pInterface = (pInterfaces->Interfaces)+u; pInterface->Buffer = (PWSTR)( (ULONG_PTR)pInterface->Buffer + (PUCHAR)pInterface);
//
// check that all this is valid...
//
if ( ((PUCHAR)pInterface->Buffer < (PUCHAR) pInterface) || ( ((PUCHAR)pInterface->Buffer + pInterface->Length) > ((PUCHAR)pInterfaces + cbInterfaces))) { printf("WHOA THERE!\n"); DebugBreak(); } else { #if 0
printf("INTERFACE: Len=%lu, Name=\"%c%c%c%c...\n", pInterface->Length, pInterface->Buffer[0], pInterface->Buffer[1], pInterface->Buffer[2], pInterface->Buffer[3] ); #endif // 0
} }
Result = TRUE; } else { DisplayMessage(FALSE, MSG_ERROR_GETTING_INTERFACE_LIST); }
return Result; }
BOOL AasGetArpCache( HANDLE DeviceHandle, INTERFACE_NAME *pInterface, PIOCTL_QUERY_CACHE pArpCache, ULONG cbArpCache ) { ULONG BytesReturned; BOOL Result = FALSE; UINT BufferOffset;
BufferOffset = FIELD_OFFSET(struct QUERY_ARP_CACHE_INPUT_PARAMS, Name) + sizeof(pArpCache->Name); pArpCache->Name.Buffer = (PWSTR)sizeof(pArpCache->Name); pArpCache->Name.Length = pInterface->Length; pArpCache->Name.MaximumLength = pInterface->MaximumLength; memcpy((PUCHAR)pArpCache + BufferOffset, pInterface->Buffer, pInterface->MaximumLength);
Result = DeviceIoControl( DeviceHandle, ARPS_IOCTL_QUERY_ARPCACHE, (PVOID)pArpCache, BufferOffset + pInterface->Length, (PVOID)pArpCache, cbArpCache, &BytesReturned, NULL);
if (Result) { #if 0
printf( "DeviceIoCtl: cbRet = %lu, cArps=%lu, cArpsInBuf=%lu\n", BytesReturned, pArpCache->Entries.TotalNumberOfEntries, pArpCache->Entries.NumberOfEntriesInBuffer ); #endif // 0
} else { DisplayMessage(FALSE, MSG_ERROR_GETTING_ARP_CACHE); }
return Result; }
BOOL AasGetMarsCache( HANDLE DeviceHandle, INTERFACE_NAME *pInterface, PIOCTL_QUERY_MARS_CACHE pMarsCache, ULONG cbMarsCache ) { ULONG BytesReturned; BOOL Result = FALSE; UINT BufferOffset;
BufferOffset = FIELD_OFFSET(struct QUERY_MARS_CACHE_INPUT_PARAMS, Name) + sizeof(pMarsCache->Name);
pMarsCache->Name.Buffer = (PWSTR)sizeof(pMarsCache->Name); pMarsCache->Name.Length = pInterface->Length; pMarsCache->Name.MaximumLength = pInterface->MaximumLength; memcpy((PUCHAR)pMarsCache + BufferOffset, pInterface->Buffer, pInterface->MaximumLength);
Result = DeviceIoControl( DeviceHandle, ARPS_IOCTL_QUERY_MARSCACHE, (PVOID)pMarsCache, BufferOffset + pInterface->Length, (PVOID)pMarsCache, cbMarsCache, &BytesReturned, NULL);
if (Result) { #if 0
printf( "DeviceIoCtl: cbRet = %lu, Sig=0x%lx, cMars=%lu, cMarsInBuf=%lu\n", BytesReturned, pMarsCache->MarsCache.Sig, pMarsCache->MarsCache.TotalNumberOfEntries, pMarsCache->MarsCache.NumberOfEntriesInBuffer ); #endif // 0
} else { DisplayMessage(FALSE, MSG_ERROR_GETTING_MARS_CACHE); }
return Result; }
BOOL AasGetArpStats( HANDLE DeviceHandle, INTERFACE_NAME *pInterface, PARP_SERVER_STATISTICS pArpStats ) { ULONG BytesReturned; BOOL Result = FALSE;
// printf ( " In AasGetArpStats\n");
//
// Temporarily fixup buffer pointer
//
pInterface->Buffer = (PWSTR)( (PUCHAR)pInterface->Buffer - (PUCHAR)pInterface);
Result = DeviceIoControl( DeviceHandle, ARPS_IOCTL_QUERY_ARP_STATISTICS, (PVOID)pInterface, (UINT) (((ULONG_PTR)pInterface->Buffer)+pInterface->Length), (PVOID)pArpStats, sizeof(*pArpStats), &BytesReturned, NULL);
//
// Restore buffer pointer
//
pInterface->Buffer = (PWSTR)( (ULONG_PTR)pInterface->Buffer + (PUCHAR)pInterface);
if (Result) { #if 0
printf( "DeviceIoCtl: cbRet = %lu, TotRcvPkts=%lu\n", BytesReturned, pArpStats->TotalRecvPkts ); #endif // 0
} else { DisplayMessage(FALSE, MSG_ERROR_GETTING_ARP_STATS); }
return Result; }
BOOL AasGetMarsStats( HANDLE DeviceHandle, INTERFACE_NAME *pInterface, PMARS_SERVER_STATISTICS pMarsStats ) { ULONG BytesReturned; BOOL Result = FALSE;
// printf ( " In AasGetMarsStats\n");
//
// Temporarily fixup buffer pointer
//
pInterface->Buffer = (PWSTR)( (PUCHAR)pInterface->Buffer - (PUCHAR)pInterface);
Result = DeviceIoControl( DeviceHandle, ARPS_IOCTL_QUERY_MARS_STATISTICS, (PVOID)pInterface, (UINT) (((ULONG_PTR)pInterface->Buffer)+pInterface->Length), (PVOID)pMarsStats, sizeof(*pMarsStats), &BytesReturned, NULL);
//
// Restore buffer pointer
//
pInterface->Buffer = (PWSTR)( (ULONG_PTR)pInterface->Buffer + (PUCHAR)pInterface);
if (Result) { #if 0
printf( "DeviceIoCtl: cbRet = %lu, TotRcvPkts=%lu\n", BytesReturned, pMarsStats->TotalRecvPkts ); #endif // 0
} else { DisplayMessage(FALSE, MSG_ERROR_GETTING_MARS_STATS); }
return Result; }
BOOL AasResetStatistics( HANDLE DeviceHandle, INTERFACE_NAME *pInterface ) { ULONG BytesReturned; BOOL Result = FALSE;
//
// Temporarily fixup buffer pointer
//
pInterface->Buffer = (PWSTR)( (PUCHAR)pInterface->Buffer - (PUCHAR)pInterface);
Result = DeviceIoControl( DeviceHandle, ARPS_IOCTL_RESET_STATISTICS, (PVOID)pInterface, (UINT) (((ULONG_PTR)pInterface->Buffer)+pInterface->Length), NULL, 0, &BytesReturned, NULL);
//
// Restore buffer pointer
//
pInterface->Buffer = (PWSTR)( (ULONG_PTR)pInterface->Buffer + (PUCHAR)pInterface);
if (Result) { DisplayMessage(FALSE, MSG_STATS_RESET_STATS); #if 0
printf( "DeviceIoCtl: cbRet = %lu, TotRcvPkts=%lu\n", BytesReturned, pMarsStats->TotalRecvPkts ); #endif // 0
} else { DisplayMessage(FALSE, MSG_ERROR_RESETTING_STATS); }
return Result; }
#if 0
LPSTR ElanStateToString(ULONG In) { switch(In) { case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: return (ElanState[In].String); default: return (ElanState[0].String); } }
LPSTR ElanLanTypeToString(ULONG In) { switch(In) { case 0: return LanType[1].String; case 1: return LanType[2].String; case 2: return LanType[3].String; default: return LanType[0].String; } }
LPSTR ElanMaxFrameSizeToString(ULONG In) { switch(In) { case 0: return Misc[3].String; case 1: return "1516"; case 2: return "4544"; case 3: return "9234"; case 4: return "18190"; default: return " ? "; } }
LPSTR McastVcTypeToString(ULONG In) { switch(In) { case 0: return McastSendVcType[1].String; case 1: return McastSendVcType[2].String; case 2: return McastSendVcType[3].String; default: return McastSendVcType[0].String; } }
PUCHAR MacAddrToString(PVOID In) { static UCHAR String[20]; static PUCHAR HexChars = "0123456789abcdef"; PUCHAR EthAddr = (PUCHAR) In; UINT i; PUCHAR s; for (i = 0, s = String; i < 6; i++, EthAddr++) { *s++ = HexChars[(*EthAddr)>>4]; *s++ = HexChars[(*EthAddr)&0xf]; *s++ = '.'; } *(--s) = '\0'; return String; } #endif // 0
PUCHAR IpAddrToString(IPADDR *pIpAddr) { PUCHAR puc = (PUCHAR) pIpAddr; static UCHAR String[80]; wsprintf(String, "%u.%u.%u.%u", puc[0], puc[1], puc[2], puc[3]); return String; }
PUCHAR AtmAddrToString(ATM_ADDRESS *pAtmAddress) { static UCHAR String[80]; static PUCHAR HexChars = "0123456789abcdef"; PUCHAR AtmAddr = (PUCHAR) &(pAtmAddress->Address); PUCHAR s = String;
*s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 1
*s++ = '.'; *s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 2
*s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 3
*s++ = '.'; *s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 4
*s++ = '.'; *s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 5
*s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 6
*s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 7
*s++ = '.'; *s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 8
*s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 9
*s++ = '.'; *s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 10
*s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 11
*s++ = '.'; *s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 12
*s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 13
*s++ = '.'; *s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 14
*s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 15
*s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 16
*s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 17
*s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 18
*s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 19
*s++ = '.'; *s++ = HexChars[(*AtmAddr)>>4]; *s++ = HexChars[(*AtmAddr++)&0xf]; // 20
*s = '\0'; return String; }
VOID AasDisplayArpCache( PIOCTL_QUERY_CACHE pArpCache ) { PARPENTRY pEntry = pArpCache->Entries.Entries; UINT i;
for (i = 0; i < pArpCache->Entries.NumberOfEntriesInBuffer; i++) { DisplayMessage(FALSE, MSG_AAS_ARP_CACHE_ENTRY, IpAddrToString(&(pEntry->IpAddr)), AtmAddrToString(&pEntry->AtmAddress));
pEntry ++; }
}
VOID AasDisplayMarsCache( PIOCTL_QUERY_MARS_CACHE pMarsCache ) {
PMARSENTRY pEntry = pMarsCache->MarsCache.Entries; UINT i;
for (i = 0; i < pMarsCache->MarsCache.NumberOfEntriesInBuffer; i++, pEntry++) { UINT j; char* szIpAddr = IpAddrToString(&(pEntry->IpAddr)); char rgBlanks[128];
ATM_ADDRESS *pAtmAddr = (ATM_ADDRESS*) ((PUCHAR)pEntry + pEntry->OffsetAtmAddresses);
FillMemory(rgBlanks, lstrlen(szIpAddr), ' '); rgBlanks[lstrlen(szIpAddr)]=0; #if 0
printf("Entry[i] @ 0x%lx: Ip=%u.%u.%u.%u NumAddr=%lu Offset=%lu\n", pEntry, ((PUCHAR)&pEntry->IpAddr)[0], ((PUCHAR)&pEntry->IpAddr)[1], ((PUCHAR)&pEntry->IpAddr)[2], ((PUCHAR)&pEntry->IpAddr)[3], pEntry->NumAtmAddresses, pEntry->OffsetAtmAddresses); #endif // 0
for (j = 0; j < pEntry->NumAtmAddresses; j++, pAtmAddr++) { // printf("\t pAddr=%lx\n", pAtmAddr);
if (!j) { if (pEntry->IpAddr == 0) { DisplayMessage(FALSE, MSG_AAS_ARP_PROMIS_CACHE_ENTRY, AtmAddrToString(pAtmAddr)); } else { DisplayMessage(FALSE, MSG_AAS_ARP_CACHE_ENTRY, IpAddrToString(&(pEntry->IpAddr)), AtmAddrToString(pAtmAddr)); }
} else { DisplayMessage(FALSE, MSG_AAS_ARP_CACHE_ENTRY, rgBlanks, AtmAddrToString(pAtmAddr)); } }
}
}
VOID AasDisplayArpStats( PARP_SERVER_STATISTICS pArpStats ) { #if 0
Recvd Pkts: ->TotalRecvPkts (->DiscardedRecvPkts discarded) Arp Entries: ->CurrentArpEntries current ( ->MaxArpEntries max) Arp Responses: ->Acks acks ( ->Naks naks) Client VCs: ->CurrentClientVCs current (->MaxClientVCs max) Incoming Calls: ->TotalIncomingCalls total (->FailedIncomingCalls failed)
Received: 10000 total (100 discarded) Entries: 10 current (15 max) Responses: 1000 acks (200 naks) Client VCs: 5 current (12 max) Incoming Calls: 500 total (20 failed) #endif //
DisplayMessage(FALSE, MSG_AAS_C01_ARP_STATS);
DisplayMessage(FALSE, MSG_STATS_ELAPSED_TIME, pArpStats->ElapsedSeconds); DisplayMessage(FALSE, MSG_ARPS_RECVD_PKTS, pArpStats->TotalRecvPkts, pArpStats->DiscardedRecvPkts); DisplayMessage(FALSE, MSG_ARPS_ARP_ENTRIES, pArpStats->CurrentArpEntries, pArpStats->MaxArpEntries); DisplayMessage(FALSE, MSG_ARPS_ARP_RESPONSES, pArpStats->Acks, pArpStats->Naks); DisplayMessage(FALSE, MSG_ARPS_CLIENT_VCS, pArpStats->CurrentClientVCs, pArpStats->MaxClientVCs); DisplayMessage(FALSE, MSG_ARPS_INCOMING_CALLS, pArpStats->TotalIncomingCalls); // pArpStats->TotalActiveVCs
}
VOID AasDisplayMarsStats( PMARS_SERVER_STATISTICS pMarsStats ) { DisplayMessage(FALSE, MSG_AAS_C02_MARS_STATS);
DisplayMessage(FALSE, MSG_MARS_RECVD_PKTS, pMarsStats->TotalRecvPkts, pMarsStats->DiscardedRecvPkts); DisplayMessage(FALSE, MSG_MARS_RECVD_MCDATA_PKTS,pMarsStats->TotalMCDataPkts, pMarsStats->DiscardedMCDataPkts, pMarsStats->ReflectedMCDataPkts); DisplayMessage(FALSE, MSG_MARS_MEMBERS, pMarsStats->CurrentClusterMembers, pMarsStats->MaxClusterMembers); DisplayMessage(FALSE, MSG_MARS_PROMIS, pMarsStats->CurrentPromiscuous, pMarsStats->MaxPromiscuous); DisplayMessage(FALSE, MSG_MARS_ADD_PARTY, pMarsStats->TotalCCVCAddParties, pMarsStats->FailedCCVCAddParties); DisplayMessage(FALSE, MSG_MARS_REGISTRATION, pMarsStats->RegistrationRequests, pMarsStats->FailedRegistrations); DisplayMessage(FALSE, MSG_MARS_JOINS, pMarsStats->TotalJoins, pMarsStats->FailedJoins, pMarsStats->DuplicateJoins); DisplayMessage(FALSE, MSG_MARS_LEAVES, pMarsStats->TotalLeaves, pMarsStats->FailedLeaves); DisplayMessage(FALSE, MSG_MARS_REQUESTS, pMarsStats->TotalRequests); DisplayMessage(FALSE, MSG_MARS_RESPONSES, pMarsStats->VCMeshAcks +pMarsStats->MCSAcks, pMarsStats->Naks); DisplayMessage(FALSE, MSG_MARS_VC_MESH, pMarsStats->SuccessfulVCMeshJoins, pMarsStats->VCMeshAcks); DisplayMessage(FALSE, MSG_MARS_GROUPS, pMarsStats->CurrentGroups, pMarsStats->MaxGroups); DisplayMessage(FALSE, MSG_MARS_GROUP_SIZE, pMarsStats->MaxAddressesPerGroup);
}
void DoAAS(OPTIONS *po) { HANDLE DeviceHandle; char InterfacesBuffer[1024]; PINTERFACES pInterfaces = (PINTERFACES) InterfacesBuffer; ULONG cbInterfaces = sizeof(InterfacesBuffer);
#if 0
PUNICODE_STRING pAdapterName; PUNICODE_STRING pElanName; ULONG i, j; BOOL Result; #endif // 0
DisplayMessage(FALSE, MSG_ATMARPS_BANNER);
DeviceHandle = OpenDevice(pDeviceName); if (DeviceHandle == INVALID_HANDLE_VALUE) { DisplayMessage(FALSE, MSG_ERROR_OPENING_ATMARPS); return; }
//
// First check the version
//
if (!CheckVersion(DeviceHandle)) { CloseDevice(DeviceHandle); return; }
//
// get the list of available adapters
//
if (!AasGetInterfaces(DeviceHandle, pInterfaces, cbInterfaces)) { CloseDevice(DeviceHandle); return; }
// printf ( " Looping through interfaces...\n");
//
// Loop thru the interfaces, displaying info about each.
//
{ UINT u=0;
for (u=0;u<pInterfaces->NumberOfInterfaces;u++) { CHAR Buffer[4000]; ULONG cbBuffer = sizeof(Buffer); PIOCTL_QUERY_CACHE pArpCache = (PIOCTL_QUERY_CACHE) Buffer; PIOCTL_QUERY_MARS_CACHE pMarsCache = (PIOCTL_QUERY_MARS_CACHE) Buffer; INTERFACE_NAME *pInterface = (pInterfaces->Interfaces)+u; PARP_SERVER_STATISTICS pArpStats = (PARP_SERVER_STATISTICS) Buffer; PMARS_SERVER_STATISTICS pMarsStats = (PMARS_SERVER_STATISTICS) Buffer; UINT StartIndex;
//
// Display the interface name -- must be null terminated.
//
{ WCHAR *pwc = pInterface->Buffer+pInterface->Length/sizeof(WCHAR); WCHAR wc = *pwc; *pwc = 0; DisplayMessage(FALSE, MSG_ADAPTER, pInterface->Buffer ); *pwc = wc; }
if (po->DispCache) { StartIndex = pArpCache->StartEntryIndex = 0;
DisplayMessage(FALSE, MSG_AAS_C00_ARP_CACHE);
while (AasGetArpCache(DeviceHandle, pInterface, pArpCache, cbBuffer) && pArpCache->Entries.NumberOfEntriesInBuffer) { AasDisplayArpCache(pArpCache); StartIndex += pArpCache->Entries.NumberOfEntriesInBuffer; pArpCache->StartEntryIndex = StartIndex; if (StartIndex == pArpCache->Entries.TotalNumberOfEntries) { break; } } StartIndex = pMarsCache->StartEntryIndex = 0;
DisplayMessage(FALSE, MSG_AAS_C00_MARS_CACHE);
while (AasGetMarsCache(DeviceHandle, pInterface, pMarsCache, cbBuffer) && pMarsCache->MarsCache.NumberOfEntriesInBuffer) { AasDisplayMarsCache(pMarsCache); StartIndex += pMarsCache->MarsCache.NumberOfEntriesInBuffer; pMarsCache->StartEntryIndex = StartIndex; } }
if (po->DispStats) { if (AasGetArpStats(DeviceHandle, pInterface, pArpStats)) { AasDisplayArpStats(pArpStats); } if (AasGetMarsStats(DeviceHandle, pInterface, pMarsStats)) { AasDisplayMarsStats(pMarsStats); } }
if (po->DoResetStats) { AasResetStatistics(DeviceHandle, pInterface); } } }
#if 0
//
// Loop thru the adapters getting each adapter's elan list
//
pAdapterName = &pAdapterList->AdapterList; for (i = 0; i < pAdapterList->AdapterCountReturned; i++) { DisplayMessage(FALSE, MSG_ADAPTER, (PWSTR)((PUCHAR)pAdapterName + sizeof(UNICODE_STRING)));
if (GetElanList(DeviceHandle, pAdapterName)) {
//
// Loop thru the elan list getting ELAN info
//
pElanName = &pElanList->ElanList; for (j = 0; j < pElanList->ElanCountReturned; j++) { DisplayMessage(FALSE, MSG_ELAN, (PWSTR)((PUCHAR)pElanName + sizeof(UNICODE_STRING)));
if (GetElanInfo(DeviceHandle, pAdapterName, pElanName)) { DisplayElanInfo(); }
if (GetElanArpTable(DeviceHandle, pAdapterName, pElanName)) { DisplayElanArpTable(); }
if (GetElanConnTable(DeviceHandle, pAdapterName, pElanName)) { DisplayElanConnTable(); }
//
// next elan
//
pElanName = (PUNICODE_STRING)((PUCHAR)pElanName + sizeof(UNICODE_STRING) + pElanName->Length); }
}
//
// next adapter
//
pAdapterName = (PUNICODE_STRING)((PUCHAR)pAdapterName + sizeof(UNICODE_STRING) + pAdapterName->Length); } #endif // 0
CloseDevice(DeviceHandle); return; }
|