I want to enumerate all Windows based machines in the network in workgroup. For that I'm using NetApi32.dll functions. In my network, I've windows, mac and linux OS installed. How can we filter out Windows Machines only. Given below is the code I am using. Please comment if I'm doing any mistake or is there any alternate method to achieve it.
BOOLEAN
LocalEnumServers(const WCHAR *pcwszDomainName) {
DWORD dwCount;
DWORD dwLevel = 101;
NET_API_STATUS Status;
HRESULT hResult = S_OK;
DWORD dwEntriesRead = 0;
BOOLEAN bResult = FALSE;
DWORD dwTotalEntries = 0;
DWORD dwResumeHandle = 0;
LPSERVER_INFO_101 pTmpBuf;
LPSERVER_INFO_101 pBuf = NULL;
TCHAR szOSName[_MAX_PATH] = _T("");
DWORD dwServerType = SV_TYPE_SERVER;
DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
if (NULL == pcwszDomainName)
{
return FALSE;
}
pBuf = NULL;
Status = NetServerEnum(
NULL,
dwLevel,
(LPBYTE *)&pBuf,
dwPrefMaxLen,
&dwEntriesRead,
&dwTotalEntries,
dwServerType,
/*(LPCSTR)*/pcwszDomainName,
&dwResumeHandle
);
if ((NERR_Success == Status || Status == ERROR_MORE_DATA) && pBuf != NULL) {
pTmpBuf = (SERVER_INFO_101 *)pBuf;
for (dwCount = 0; dwCount < dwEntriesRead; dwCount++) {
wprintf(L"Server name = %15s, Server type = 0x%08X, Verson = (%u:%u), Comment = %s\n", pTmpBuf[dwCount].sv101_name, pTmpBuf[dwCount].sv101_type, pTmpBuf[dwCount].sv101_version_major & MAJOR_VERSION_MASK, pTmpBuf[dwCount].sv101_version_minor, pTmpBuf[dwCount].sv101_comment);
//wprintf(L"Server name -> %s, Server type -> 0x%X, Platform ID -> 0x%X, Verson -> (%u:%u)\n", pTmpBuf[dwCount].sv101_name, pTmpBuf[dwCount].sv101_type, pTmpBuf[dwCount].sv101_platform_id, pTmpBuf[dwCount].sv101_version_major & MAJOR_VERSION_MASK, pTmpBuf[dwCount].sv101_version_minor);
if (
SV_TYPE_WINDOWS != (SV_TYPE_WINDOWS & pTmpBuf[dwCount].sv101_type) &&
SV_TYPE_SERVER_NT != (SV_TYPE_SERVER_NT & pTmpBuf[dwCount].sv101_type) &&
SV_TYPE_NT != (SV_TYPE_NT & pTmpBuf[dwCount].sv101_type)
) {
wprintf(L"Flag check (%u, %u, %u)\n", SV_TYPE_WINDOWS != (SV_TYPE_WINDOWS & pTmpBuf[dwCount].sv101_type),
SV_TYPE_SERVER_NT != (SV_TYPE_SERVER_NT & pTmpBuf[dwCount].sv101_type),
SV_TYPE_NT != (SV_TYPE_NT & pTmpBuf[dwCount].sv101_type));
continue;
}
}
}
else {
wprintf(L"NetServerEnum failed (Err -> %u)\n", GetLastError());
}
if (pBuf != NULL) {
NetApiBufferFree(pBuf);
}
return TRUE;
}
int _tmain(int argc, _TCHAR* argv[]) {
LocalEnumServers(L"workgroup");
return 0;
}
For UNIX type system you can add if condition and perform AND with predefined macro for unix system and sv type u r getting. But for MAC there is an issue.
Related
I am trying to get the base string in the DLL using EvtFormatMessage but no matter what I do its not working. The windows help page made it sound like you can use the values and valuecount parameters to change the default behavior but when I change them nothing is printed.
Another attempt I made was to go through the publishers metadata and match it with the correct eventId and version but the EvtOpenEventMetadatEnum has no items for it to iterate through for all events publishers. It works for time change events but not for other events.
This is the code I have to return the message string. hMetadata is the publisher metadata and hEvent is the event metadata
LPWSTR GetMessageString(EVT_HANDLE hMetadata, EVT_HANDLE hEvent, EVT_FORMAT_MESSAGE_FLAGS FormatId, DWORD MsgID)
{
LPWSTR pBuffer = NULL;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD status = ERROR_SUCCESS;
if (!fpEvtFormatMessage(hMetadata, hEvent, MsgID, 0, NULL, FormatId, dwBufferSize, pBuffer, &dwBufferUsed))
{
status = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == status)
{
// An event can contain one or more keywords. The function returns keywords
// as a list of keyword strings. To process the list, you need to know the
// size of the buffer, so you know when you have read the last string, or you
// can terminate the list of strings with a second null terminator character
// as this example does.
if ((EvtFormatMessageKeyword == FormatId))
pBuffer[dwBufferSize - 1] = L'\0';
else
dwBufferSize = dwBufferUsed;
pBuffer = (LPWSTR)malloc(dwBufferSize * sizeof(WCHAR));
if (pBuffer)
{
fpEvtFormatMessage(hMetadata, hEvent, MsgID, 0, NULL, FormatId, dwBufferSize, pBuffer, &dwBufferUsed);
// Add the second null terminator character.
if ((EvtFormatMessageKeyword == FormatId))
pBuffer[dwBufferUsed - 1] = L'\0';
}
else
{
TRACE5(_T("malloc failed\n"));
}
}
else if (ERROR_EVT_MESSAGE_NOT_FOUND == status || ERROR_EVT_MESSAGE_ID_NOT_FOUND == status)
;
else
{
TRACE5(_T("EvtFormatMessage failed with %u\n"), status);
}
}
This is the code that is supposed to match the event I have with the template event in the dll
hEvents = fpEvtOpenEventMetadataEnum(g_hMetadata, 0);
if (NULL == hEvents)
{
TRACE5(_T("EvtOpenEventMetadataEnum failed with %lu\n"), GetLastError());
goto cleanup;
}
// Enumerate the events and print each event's metadata.
while (run)
{
hEvent = fpEvtNextEventMetadata(hEvents, 0);
if (NULL == hEvent)
{
if (ERROR_NO_MORE_ITEMS != (status = GetLastError()))
{
TRACE5(_T("EvtNextEventMetadata failed with %lu\n"), status);
}
break;
}
msgId = getEventID(g_hMetadata, hEvent, &tempVersion);
if (dwMsgID == msgId && tempVersion == version) {
PEVT_VARIANT pProperty = NULL; // Contains a metadata value
PEVT_VARIANT pTemp = NULL;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD status2 = ERROR_SUCCESS;
if (!fpEvtGetEventMetadataProperty(hEvent, EventMetadataEventMessageID, 0, dwBufferSize, pProperty, &dwBufferUsed))
{
status2 = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == status2)
{
dwBufferSize = dwBufferUsed;
pTemp = (PEVT_VARIANT)realloc(pProperty, dwBufferSize);
if (pTemp)
{
pProperty = pTemp;
pTemp = NULL;
fpEvtGetEventMetadataProperty(hEvent, EventMetadataEventMessageID, 0, dwBufferSize, pProperty, &dwBufferUsed);
}
else
{
TRACE5(_T("realloc failed\n"));
status2 = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status2 = GetLastError()))
{
TRACE5(_T("EvtGetEventMetadataProperty failed with %d\n"), GetLastError());
goto cleanup;
}
}
if (-1 == pProperty->UInt32Val)
{
*pStrNonExpLibMsg = "Message string: \n";
}
else
{
*pStrNonExpLibMsg = GetMessageString(g_hMetadata, NULL, EvtFormatMessageId, pProperty->UInt32Val);
if (pMessage)
{
free(pMessage);
}
}
run = false;
break;
}
fpEvtClose(hEvent);
hEvent = NULL;
}
cleanup:
if (hEvents)
fpEvtClose(hEvents);
if (hEvent)
fpEvtClose(hEvent);
return status;
}
DWORD getEventID(EVT_HANDLE g_hMetadata, EVT_HANDLE hEvent, DWORD *evtVersion)
{
PEVT_VARIANT pProperty = NULL; // Contains a metadata value
PEVT_VARIANT pTemp = NULL;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD status = ERROR_SUCCESS;
DWORD retValue = NULL;
// Get the specified metadata property. If the pProperty buffer is not big enough, reallocate the buffer.
for (int i = 0; i < 2; i++)
{
if (!fpEvtGetEventMetadataProperty(hEvent, (EVT_EVENT_METADATA_PROPERTY_ID)i, 0, dwBufferSize, pProperty, &dwBufferUsed))
{
status = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == status)
{
dwBufferSize = dwBufferUsed;
pTemp = (PEVT_VARIANT)realloc(pProperty, dwBufferSize);
if (pTemp)
{
pProperty = pTemp;
pTemp = NULL;
fpEvtGetEventMetadataProperty(hEvent, (EVT_EVENT_METADATA_PROPERTY_ID)i, 0, dwBufferSize, pProperty, &dwBufferUsed);
}
else
{
TRACE5(_T("realloc failed\n"));
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
TRACE5(_T("EvtGetEventMetadataProperty failed with %d\n"), GetLastError());
goto cleanup;
}
}
if (i == 0)
{
retValue = pProperty->UInt32Val;
}
else
{
*evtVersion = pProperty->UInt32Val;
}
RtlZeroMemory(pProperty, dwBufferUsed);
}
The short version:
I have written a small program to print a report. This program is exec'ed from our proprietary server, that is running as a windows service. It works in our development environment, but not on our customer's network.
When I attempt to access the printing system in the failing case, I get a "No default printer" error. We had the customer create a new login account that has a default printer defined, and restarted the server using that login account. Same error.
Note that this error is generated when trying to find a specified printer, not when we try to print to it.
Is there any way to convince a server-spawned process that printers do, in fact, exist?
The long version:
In our "current" production environment, we have the following:
1. a proprietary server that runs as a service under windows.
2. a desktop client
--> accesses data via that service
--> uses fastreport4 to generate reports
--> developed using C++Builder6 (and VCL)
3. a PocketPC-based application that runs on scanning devices
--> uses Apache to communicate with the service
--> also uses Apache to poke a cgi-bin application that will bring up
the desktop app in stealth mode, run a report, and print it.
I have been tasked with re-implementing the Pocket-PC functionality on an Android-based scanning device, and removing the Apache layer from the architecture. In the Android app, I've written a communication layer to access the server (service) directly (the same way the desktop does). The server has the ability to exec applications, so I've written a small one to just gather data, and call fastreport to format and print it.
Works great. No problem. ... in our development environment. It works in our office network with the server running on a Windows 7 system. It works when run from the command line on our customer's Windows 2008 server. It does not work when run from the service on the customer's server.
So here's the code. In my current revision, I have try/catch and debug print statements around (nearly) every line of code. I removed them for readability.
bool __fastcall TFormReportRunner::mySetPrinter(const char* name)
{
char pDevice[MAX_PATH];
char pDriver[MAX_PATH];
char APort[100];
UINT ADeviceMode;
bool printerFound = false;
bool errorFound = false;
String PrinterPort = String(name).UpperCase();
TPrinter* Prntr;
// I added this bit to see if it helps. Seems to make no difference
bool rc = SetDefaultPrinter("");
Prntr = Printer();
if (Prntr == NULL)
{
LogErrorMsg("Printer() returned null.");
return false;
}
int i = Prntr->Printers->Count - 1;
for (; i >= 0; i--)
{
// In the failing case, this next statement is the one that causes an exception.
Prntr->PrinterIndex = i;
Prntr->GetPrinter(pDevice, pDriver, APort, ADeviceMode);
DWORD SizeNeeded = 0;
HANDLE PrinterHandle;
if (OpenPrinter(pDevice, &PrinterHandle, NULL) == 0)
{
LogErrorMsg("Could not open printer");
return false;
}
GetPrinter(PrinterHandle, 2, NULL, 0, &SizeNeeded);
if (SizeNeeded == 0)
{
ClosePrinter(PrinterHandle);
LogErrorMsg("Could not retrieve printer info size");
return false;
}
PRINTER_INFO_2 PrinterInfo2;
char* buffer = new char[SizeNeeded];
if (GetPrinter(PrinterHandle, 2, buffer, SizeNeeded, &SizeNeeded) == 0)
{
ClosePrinter(PrinterHandle);
delete [] buffer;
LogErrorMsg("Could not retrieve printer info");
return false;
}
String PortName = ((PRINTER_INFO_2*)buffer)->pPortName;
delete [] buffer;
ClosePrinter(PrinterHandle);
if (PrinterPort == PortName)
{
frxReport1->PrintOptions->Printer = pDevice;
break;
}
}
Prntr->PrinterIndex = i;
return true;
}
One of the customer's IT guys says that in order to have the Apache version work they have to run Apache as administrator with a defined default printer AND have that admin account logged in for printing to work. He suspects that if we run our service in the same configuration it will start to work. I have not been able to replicate that on our network. My admin account always works, whether anyone is currently logged into the system, or not. But this is Windows 7/Professional, and not a server version.
This has got to be possible... Apache's doing it. If it can find a printer and print to it, I should be able to, right?
Any hints or help will be greatly appreciated. Anything. Really. :)
Thanks,
-Karen
Edit: Adding server-side code.
A couple of notes, first. One, this was written 20-ish years ago (by someone else). Two, it is NOT a VCL app (and was compiled with the Microsoft compiler). Three, we will not change it. Recompiling with current compilers is WAY too risky for something that is otherwise working.
int myServer::RunProcess2(ClientCall *call, vector<string> &args, vector<string> &env, const char* input, unsigned int insize,
string *output, string *error)
{
CancelProcess2(); // only one process allowed per connection
string cmdline;
for (unsigned int i = 0; i < args.size(); i++)
{
if (i != 0)
cmdline += ' ';
cmdline += args[i];
}
env.push_back(EnvPATH);
int size = 1;
for (unsigned int i = 0; i < env.size(); i++)
{
size += env[i].size() + 1;
}
char *environment = (char*)malloc(size);
if (environment == NULL)
{
call->error = "Could not allocate memory for process environment variables";
return 0;
}
char *ptr = environment;
for (unsigned int i = 0; i < env.size(); i++)
{
size = env[i].size() + 1;
memcpy(ptr, env[i].c_str(), size);
ptr += size;
}
ptr[0] = '\0';
HANDLE hInputReadPipe = NULL, hInputWritePipe = NULL;
HANDLE hReadPipe, hWritePipe;
HANDLE hErrorReadPipe, hErrorWritePipe;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = true;
// create output pipe
if (CreatePipe(&hReadPipe, &hWritePipe, &sa, 4096) == 0)
{
free(environment);
call->error = "Error creation Pipe";
return 0;
}
// create error pipe
if (CreatePipe(&hErrorReadPipe, &hErrorWritePipe, &sa, 4096) == 0)
{
CloseHandle(hReadPipe);
CloseHandle(hWritePipe);
free(environment);
call->error = "Error creating Pipe";
return 0;
}
if (insize > 0)
{
// create input pipe
if (CreatePipe(&hInputReadPipe, &hInputWritePipe, &sa, 4096) == 0)
{
CloseHandle(hReadPipe);
CloseHandle(hWritePipe);
CloseHandle(hErrorReadPipe);
CloseHandle(hErrorWritePipe);
free(environment);
call->error = "Error creating Pipe";
return 0;
}
}
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdOutput = hWritePipe;
si.hStdError = hErrorWritePipe;
si.hStdInput = hInputReadPipe;
PROCESS_INFORMATION pi;
if (CreateProcess(NULL, (char*)cmdline.c_str(), NULL, NULL, true, 0, environment, NULL, &si, &pi) == 0)
{
CloseHandle(hErrorReadPipe);
CloseHandle(hErrorWritePipe);
CloseHandle(hReadPipe);
CloseHandle(hWritePipe);
if (hInputReadPipe != NULL)
{
CloseHandle(hInputReadPipe);
CloseHandle(hInputWritePipe);
}
free(environment);
call->error = string("Error executing command: ") + cmdline + "\n" + GetErrorText();
return 0;
}
report_handle = pi.hProcess;
CloseHandle(hErrorWritePipe);
CloseHandle(hWritePipe);
if (hErrorReadPipe != NULL)
CloseHandle(hInputReadPipe);
char buffer[4097];
DWORD BytesAvail;
DWORD BytesRead = 0;
DWORD BytesWritten = 0;
DWORD BytesToRead = sizeof(buffer) - 1;
DWORD BytesToWrite = insize;
bool finished_readpipe = false, finished_errorpipe = false;
bool finished_inputpipe = (insize == 0);
int wait_time = 1;
bool error_occurred = false;
while (finished_readpipe == false || finished_errorpipe == false || finished_inputpipe == false)
{
if (finished_inputpipe == false)
{
if (BytesToWrite <= 0)
{
CloseHandle(hInputWritePipe);
hInputWritePipe = NULL;
finished_inputpipe = true;
continue;
}
BytesAvail = 1000;
/*if (PeekNamedPipe(hInputWritePipe, NULL, NULL, NULL, &BytesAvail, NULL) == 0)
{
DWORD temp = GetLastError();
// pipe has been closed
finished_inputpipe = true;
continue;
}*/
if (BytesAvail > 0)
{
if (BytesAvail > BytesToWrite)
BytesAvail = BytesToWrite;
if (WriteFile(hInputWritePipe, input, BytesAvail, &BytesWritten, NULL) == 0)
{
if (GetLastError() == ERROR_NO_DATA)
{
int a = 2; // Pipe was closed (normal exit path).
}
finished_inputpipe = true;
continue;
}
input += BytesWritten;
BytesToWrite -= BytesWritten;
if (BytesToWrite == 0)
{
finished_inputpipe = true;
}
continue;
}
}
if (finished_readpipe == false)
{
while (true)
{
if (PeekNamedPipe(hReadPipe, NULL, NULL, NULL, &BytesAvail, NULL) == 0)
{
// pipe has been closed
finished_readpipe = true;
break;
}
if (BytesAvail <= 0)
break;
if (BytesAvail > sizeof(buffer) - 1)
BytesAvail = sizeof(buffer) - 1;
if (ReadFile(hReadPipe, buffer, BytesAvail, &BytesRead, NULL) == 0)
{
finished_readpipe = true;
break;
}
if (BytesRead == 0)
{
finished_readpipe = true;
break;
}
buffer[BytesRead] = '\0';
*output += buffer;
if (output->length() >= MAX_PROCESS_OUTPUT)
{
finished_inputpipe = true;
finished_readpipe = true;
finished_errorpipe = true;
error_occurred = true;
call->error = "Output limit reached";
}
}
if (finished_readpipe == true)
continue;
}
if (finished_errorpipe == false)
{
while (true)
{
if (PeekNamedPipe(hErrorReadPipe, NULL, NULL, NULL, &BytesAvail, NULL) == 0)
{
// pipe has been closed
finished_errorpipe = true;
break;
}
if (BytesAvail <= 0)
break;
if (BytesAvail > sizeof(buffer) - 1)
BytesAvail = sizeof(buffer) - 1;
if (ReadFile(hErrorReadPipe, buffer, BytesAvail, &BytesRead, NULL) == 0)
{
finished_errorpipe = true;
break;
}
if (BytesRead == 0)
{
finished_errorpipe = true;
break;
}
buffer[BytesRead] = '\0';
*error += buffer;
if (error->length() >= MAX_PROCESS_OUTPUT)
{
finished_inputpipe = true;
finished_readpipe = true;
finished_errorpipe = true;
error_occurred = true;
call->error = "Error output limit reached";
}
}
if (finished_errorpipe == true)
continue;
}
// don't tie up the server
if (wait_time < 100)
wait_time++;
Sleep(wait_time);
}
if (error_occurred == false)
WaitForSingleObject(pi.hProcess, INFINITE);
process_mutex.lock();
report_handle = NULL;
process_mutex.unlock();
DWORD exit_code = 0;
GetExitCodeProcess(pi.hProcess, &exit_code);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(hReadPipe);
CloseHandle(hErrorReadPipe);
if (hInputWritePipe != NULL)
CloseHandle(hInputWritePipe);
free(environment);
return exit_code;
}
My program normally detects what Serial Ports are available from the OS at start up. It is a simple method of polling if a port can be accessed by name.
project defines for serial port
std::string COMPortNumber[MAXPORTS] {"\\\\.\\COM1", "\\\\.\\COM2", "\\\\.\\COM3", "\\\\.\\COM4", "\\\\.\\COM5",
"\\\\.\\COM6", "\\\\.\\COM7", "\\\\.\\COM8", "\\\\.\\COM9", "\\\\.\\COM10",
"\\\\.\\COM11", "\\\\.\\COM12", "\\\\.\\COM13", "\\\\.\\COM14", "\\\\.\\COM15",
"\\\\.\\COM16", "\\\\.\\COM17", "\\\\.\\COM18", "\\\\.\\COM19", "\\\\.\\COM20"};
std::string COMPortName[MAXPORTS] = {"com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9", "com10",
"com11", "com12", "com13", "com14", "com15", "com16", "com17", "com18", "com19", "com20"};
polling function:
void updateSerialList(){
ComboBox_ResetContent(SerialPortDropDown); //clears all content from drop down box
//int iresult = ComboBox_AddString(SerialPortDropDown, "Update Port List\0");
for(int n=0; n<MAXPORTS; n++)
{
COMPortAvailable[n] = serial.getComPortList( COMPortNumber[n] );
if(COMPortAvailable[n] == true)
{
char* tempBuf = new char[COMPortName[n].length() + 1];
for(unsigned int t=0; t<COMPortName[n].length(); t++)
{
tempBuf[t] = COMPortName[n][t];
}
tempBuf[COMPortName[n].length()] = '\0';
int iResult = ComboBox_AddString(SerialPortDropDown, tempBuf);
{
if(iResult == CB_ERR){std::cout << "error adding string" << std::endl;}
else if(iResult == CB_ERRSPACE){std::cout << "error no room" << std::endl;}
}
delete[] tempBuf;
}
}
//place baud rates in select box
for(int n=NUMBERBAUDRATES-1; n>-1; n--)
{
char* tempBuf = new char[BaudRateName[n].length() + 1];
for(unsigned int t=0; t<BaudRateName[n].length(); t++)
{
tempBuf[t] = BaudRateName[n][t];
}
tempBuf[BaudRateName[n].length()] = '\0';
int iResult = ComboBox_AddString(BaudRateDropDown, tempBuf);
{
if(iResult == CB_ERR){std::cout << "error adding string" << std::endl;}
else if(iResult == CB_ERRSPACE){std::cout << "error no room" << std::endl;}
}
delete[] tempBuf;
}
This compiles a list in a dropdown box for the user to select. It uses a function in a class for a serial instance. This is the function call inside the class.
bool getComPortList(std::string portName)
{
bool test;
HANDLE testSerial;
testSerial = CreateFile( (portName.c_str()) , GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, NULL, NULL);
if(testSerial == INVALID_HANDLE_VALUE)
{
test = false;
}
else
{
test = true;
cout << "port number " << portName << " is available" << endl;
}
CloseHandle(testSerial);
return test;
}
This method has worked fine until I tried running the program on Windows 10. It previously was tested and used on Vista, Win7, Win 8.1 however even if the Windows10 device manager says comm ports are available on the system, my program cannot get a list of them.
What is different about Win10 serial port access?
your main logic error, that you assume - if CreateFile for some name return INVALID_HANDLE_VALUE - this mean that this name not exist. but this is of course false, because CreateFile can fail by different reasons. you need call GetLastError after fail. only if it return ERROR_FILE_NOT_FOUND the name really not exist (ERROR_PATH_NOT_FOUND can not be for "\\\\.\\COMX" because path here always exist and correct). for com devices very common error was STATUS_ACCESS_DENIED - because it have DO_EXCLUSIVE flag. with this flag only one file on device can be open at a time.
however for enumerate com devices - you need enumerate interfaces for GUID_DEVINTERFACE_COMPORT via CM_Get_Device_Interface_ListW
enumInterfaces(const_cast<PGUID>(&GUID_DEVINTERFACE_COMPORT));
static volatile UCHAR guz;
void enumInterfaces(PGUID InterfaceClassGuid)
{
CONFIGRET status;
ULONG len = 0, cb = 0, rcb;
PVOID stack = alloca(guz);
PWSTR buf = 0;
do
{
if (status = CM_Get_Device_Interface_List_SizeW(&len, InterfaceClassGuid, 0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
break;
}
if (cb < (rcb = len * sizeof(WCHAR)))
{
len = (cb = RtlPointerToOffset(buf = (PWSTR)alloca(rcb - cb), stack)) / sizeof(WCHAR);
}
status = CM_Get_Device_Interface_ListW(InterfaceClassGuid, 0, buf, len, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (status == CR_SUCCESS)
{
while (*buf)
{
DbgPrint("use this name in CreateFile = %S\n", buf);
PrintFriendlyNameByInterface(buf);
buf += 1 + wcslen(buf);
}
}
} while (status == CR_BUFFER_SMALL);
}
CONFIGRET PrintFriendlyNameByInterface(PCWSTR pszDeviceInterface)
{
ULONG cb = 0, rcb = 64;
PVOID stack = alloca(guz);
DEVPROPTYPE PropertyType;
CONFIGRET status;
union {
PVOID pv;
PWSTR DeviceID;
PBYTE pb;
};
do
{
if (cb < rcb)
{
rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
}
status = CM_Get_Device_Interface_PropertyW(pszDeviceInterface, &DEVPKEY_Device_InstanceId, &PropertyType, pb, &rcb, 0);
if (status == CR_SUCCESS)
{
if (PropertyType == DEVPROP_TYPE_STRING)
{
DbgPrint("DeviceID = %S\n", DeviceID);
status = PrintFriendlyNameByDeviceID(DeviceID);
}
else
{
status = CR_WRONG_TYPE;
}
break;
}
} while (status == CR_BUFFER_SMALL);
return status;
}
CONFIGRET PrintFriendlyNameByDeviceID(PWSTR DeviceID)
{
DEVINST dnDevInst;
CONFIGRET status = CM_Locate_DevNodeW(&dnDevInst, DeviceID, CM_LOCATE_DEVNODE_NORMAL);
if (status == CR_SUCCESS)
{
ULONG cb = 0, rcb = 256;
PVOID stack = alloca(guz);
DEVPROPTYPE PropertyType;
union {
PVOID pv;
PWSTR sz;
PBYTE pb;
};
do
{
if (cb < rcb)
{
rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
}
status = CM_Get_DevNode_PropertyW(dnDevInst, &DEVPKEY_NAME, &PropertyType, pb, &rcb, 0);
if (status == CR_SUCCESS)
{
if (PropertyType == DEVPROP_TYPE_STRING)
{
DbgPrint("show this name for user = %S\n", sz);
}
else
{
status = CR_WRONG_TYPE;
}
}
} while (status == CR_BUFFER_SMALL);
}
return status;
}
and demo output:
use this name in CreateFile = \\?\ACPI#PNP0501#0#{86e0d1e0-8089-11d0-9ce4-08003e301f73}
DeviceID = ACPI\PNP0501\0
show this name for user = Communications Port (COM1)
in my system \\?\ACPI#PNP0501#0#{86e0d1e0-8089-11d0-9ce4-08003e301f73} is symbolic link to PDO device \Device\00000034 (created by aspi.sys) and it have not DO_EXCLUSIVE flag. despite this on second call of CreateFile i got access denied error. to this device FDO - \Device\Serial0 (\\?\COM1 symbolic link to it) attached. it already have DO_EXCLUSIVE flag. anyway SerialCreateOpen (IRP_MJ_CREATE procedure serial.sys) denied access create more than one file - at very begin in increment some counter in device extension, and if it != 1 - return STATUS_ACCESS_DENIED
so even if we try open PDO (\\?\ACPI#PNP0501#0#{86e0d1e0-8089-11d0-9ce4-08003e301f73}) which not exclusive device (setting the exclusive flag for the FDO has no effect here) - the create request begin execute on stack top from \Device\Serial0 and serial.sys enforce exclusivity themselves within their SerialCreateOpen routine.
I want write program for on/off wifi modules on C++ NativeWifi.
I received All modules.Then I do not know what to do.I have no experience in NativeWifi Api.Please help me, thank.
HANDLE hClient = NULL;
DWORD dwMaxClient = 2; //
DWORD dwCurVersion = 0;
DWORD dwResult = 0;
DWORD dwRetVal = 0;
int iRet = 0;
WCHAR GuidString[39] = { 0 };
unsigned int i, j, k;
/* variables used for WlanEnumInterfaces */
PWLAN_INTERFACE_INFO_LIST pIfList = NULL;
PWLAN_INTERFACE_INFO pIfInfo = NULL;
PWLAN_AVAILABLE_NETWORK_LIST pBssList = NULL;
PWLAN_AVAILABLE_NETWORK pBssEntry = NULL;
dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient);
if (dwResult != ERROR_SUCCESS) {
wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult);
return 1;
// You can use FormatMessage here to find out why the function failed
}
dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList);
if (dwResult != ERROR_SUCCESS) {
wprintf(L"WlanEnumInterfaces failed with error: %u\n", dwResult);
return 1;
// You can use FormatMessage here to find out why the function failed
}
else {
wprintf(L"Num Entries: %lu\n", pIfList->dwNumberOfItems);
wprintf(L"Current Index: %lu\n", pIfList->dwIndex);
for (i = 0; i < (int)pIfList->dwNumberOfItems; i++) {
pIfInfo = (WLAN_INTERFACE_INFO *)&pIfList->InterfaceInfo[i];
wprintf(L" Interface Index[%u]:\t %lu\n", i, i);
iRet = StringFromGUID2(pIfInfo->InterfaceGuid, (LPOLESTR)&GuidString,
sizeof(GuidString) / sizeof(*GuidString));
// For c rather than C++ source code, the above line needs to be
// iRet = StringFromGUID2(&pIfInfo->InterfaceGuid, (LPOLESTR) &GuidString,
// sizeof(GuidString)/sizeof(*GuidString));
if (iRet == 0)
wprintf(L"StringFromGUID2 failed\n");
else {
wprintf(L" InterfaceGUID[%d]: %ws\n", i, GuidString);
}
}
}
I received All modules.Next, The radio state of a PHY is off if either dot11SoftwareRadioState or dot11HardwareRadioState member of the WLAN_PHY_RADIO_STATE structure is dot11_radio_state_off.
As the documentation of WLAN_PHY_RADIO_STATE states, you can use WlanSetInterface to turn the software radio state off.
I'm using the excellent tool provided by Nate True # http://devices.natetrue.com/macshift/
It changes the Mac address by the adapter name. This is the source code:
const int versionMajor = 1;
const int versionMinor = 1;
#include <windows.h>
#include <objbase.h>
#include <netcon.h>
#include <stdio.h>
#include "validmacs.h"
void SetMAC(char * AdapterName, char * NewMAC) {
HKEY hListKey = NULL;
HKEY hKey = NULL;
RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
0, KEY_READ, &hListKey);
if (!hListKey) {
printf("Failed to open adapter list key\n");
return;
}
FILETIME writtenTime;
char keyNameBuf[512], keyNameBuf2[512];
DWORD keyNameBufSiz = 512;
DWORD crap;
int i = 0;
bool found = false;
while (RegEnumKeyEx(hListKey, i++, keyNameBuf, &keyNameBufSiz, 0, NULL, NULL, &writtenTime)
== ERROR_SUCCESS) {
_snprintf(keyNameBuf2, 512, "%s\\Connection", keyNameBuf);
hKey = NULL;
RegOpenKeyEx(hListKey, keyNameBuf2, 0, KEY_READ, &hKey);
if (hKey) {
keyNameBufSiz = 512;
if (RegQueryValueEx(hKey, "Name", 0, &crap, (LPBYTE)keyNameBuf2, &keyNameBufSiz)
== ERROR_SUCCESS && strcmp(keyNameBuf2, AdapterName) == 0) {
printf("Adapter ID is %s\n", keyNameBuf);
found = true;
break;
}
RegCloseKey(hKey);
}
keyNameBufSiz = 512;
}
RegCloseKey(hListKey);
if (!found) {
printf("Could not find adapter name '%s'.\nPlease make sure this is the name you gave it in Network Connections.\n", AdapterName);
return;
}
RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}",
0, KEY_READ, &hListKey);
if (!hListKey) {
printf("Failed to open adapter list key in Phase 2\n");
return;
}
i = 0;
char buf[512];
while (RegEnumKeyEx(hListKey, i++, keyNameBuf2, &keyNameBufSiz, 0, NULL, NULL, &writtenTime)
== ERROR_SUCCESS) {
hKey = NULL;
RegOpenKeyEx(hListKey, keyNameBuf2, 0, KEY_READ | KEY_SET_VALUE, &hKey);
if (hKey) {
keyNameBufSiz = 512;
if ((RegQueryValueEx(hKey, "NetCfgInstanceId", 0, &crap, (LPBYTE)buf, &keyNameBufSiz)
== ERROR_SUCCESS) && (strcmp(buf, keyNameBuf) == 0)) {
RegSetValueEx(hKey, "NetworkAddress", 0, REG_SZ, (LPBYTE)NewMAC, strlen(NewMAC) + 1);
//printf("Updating adapter index %s (%s=%s)\n", keyNameBuf2, buf, keyNameBuf);
//break;
}
RegCloseKey(hKey);
}
keyNameBufSiz = 512;
}
RegCloseKey(hListKey);
}
void ResetAdapter(char * AdapterName) {
struct _GUID guid = {0xBA126AD1,0x2166,0x11D1,0};
memcpy(guid.Data4, "\xB1\xD0\x00\x80\x5F\xC1\x27\x0E", 8);
unsigned short * buf = new unsigned short[strlen(AdapterName)+1];
void (__stdcall *NcFreeNetConProperties) (NETCON_PROPERTIES *);
HMODULE NetShell_Dll = LoadLibrary("Netshell.dll");
if (!NetShell_Dll) {
printf("Couldn't load Netshell.dll\n");
return;
}
NcFreeNetConProperties = (void (__stdcall *)(struct tagNETCON_PROPERTIES *))GetProcAddress(NetShell_Dll, "NcFreeNetconProperties");
if (!NcFreeNetConProperties) {
printf("Couldn't load required DLL function\n");
return;
}
for (unsigned int i = 0; i <= strlen(AdapterName); i++) {
buf[i] = AdapterName[i];
}
CoInitialize(0);
INetConnectionManager * pNCM = NULL;
HRESULT hr = ::CoCreateInstance(guid,
NULL,
CLSCTX_ALL,
__uuidof(INetConnectionManager),
(void**)&pNCM);
if (!pNCM)
printf("Failed to instantiate required object\n");
else {
IEnumNetConnection * pENC;
pNCM->EnumConnections(NCME_DEFAULT, &pENC);
if (!pENC) {
printf("Could not enumerate Network Connections\n");
}
else {
INetConnection * pNC;
ULONG fetched;
NETCON_PROPERTIES * pNCP;
do {
pENC->Next(1, &pNC, &fetched);
if (fetched && pNC) {
pNC->GetProperties(&pNCP);
if (pNCP) {
if (wcscmp(pNCP->pszwName, buf) == 0) {
pNC->Disconnect();
pNC->Connect();
}
NcFreeNetConProperties(pNCP);
}
}
} while (fetched);
pENC->Release();
}
pNCM->Release();
}
FreeLibrary(NetShell_Dll);
CoUninitialize ();
}
bool IsValidMAC(char * str) {
if (strlen(str) != 12) return false;
for (int i = 0; i < 12; i++) {
if ((str[i] < '0' || str[i] > '9')
&& (str[i] < 'a' || str[i] > 'f')
&& (str[i] < 'A' || str[i] > 'F')) {
return false;
}
}
return true;
}
void ShowHelp() {
printf("Usage: macshift [options] [mac-address]\n\n");
printf("Options:\n");
printf("\t-i [adapter-name] The adapter name from Network Connections.\n");
printf("\t-r Uses a random MAC address. This is the default.\n");
printf("\t-d Restores the original MAC address.\n");
printf("\t--help Shows this screen.\n\n");
printf("Macshift uses special undocumented functions in the Windows COM Interface that\n");
printf(" allow you to change an adapter's MAC address without needing to restart.\n");
printf("When you change a MAC address, all your connections are closed automatically\n");
printf(" and your adapter is reset.\n");
}
//Generates a random MAC that is actually plausible
void RandomizeMAC(char * newmac) {
_snprintf(newmac, 6, "%06X", rand() % numMacs);
for (int i = 3; i < 6; i++) {
_snprintf(&newmac[i*2], 2, "%02X", rand() & 0xFF);
}
newmac[12] = 0;
}
int main(int argc, char * * argv) {
printf("Macshift v%i.%i, MAC Changing Utility by Nathan True, macshift#natetrue.com\n\n", versionMajor, versionMinor);
//Parse commandline arguments
char * adapter = "Wireless";
char newmac[13];
int i;
if (argc == 1) {
ShowHelp();
return 0;
}
//Start out with a random MAC
srand(GetTickCount());
RandomizeMAC(newmac);
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case '-': //Extended argument
if (strcmp(argv[i]+2, "help") == 0) {
ShowHelp();
return 0;
}
break;
case 'r': //Random setting, this is the default
break;
case 'i': //Adapter name follows
if (argc > i + 1) adapter = argv[++i];
break;
case 'd': //Reset the MAC address
newmac[0] = 0;
}
}
else {
if (IsValidMAC(argv[i])) strncpy(newmac, argv[i], 13);
else printf("MAC String %s is not valid. MAC addresses must m/^[0-9a-fA-F]{12}$/.\n", argv[i]);
}
}
printf("Setting MAC on adapter '%s' to %s...\n", adapter, newmac[0] ? newmac : "original MAC");
SetMAC(adapter, newmac);
printf("Resetting adapter...\n");
fflush(stdout);
ResetAdapter(adapter);
printf("Done\n");
return 0;
}
I would like to change the Mac address by the description of an adapter, in addition to the name. So I need to modify this code so that if a matching name is not found, it falls back to changing the mac based on the description.
This is an example adapter:
name: Local Area Connection
description: Marvell Yukon 88E8055 PCI-E Gigabit Ethernet Controller
Unfortunately, being a Java developer I have limited experience with C++, so any help would be greatly appreciated.
Here's a C sample of GetAdaptersInfo, it prints out each adapters name and description (you can easily adapt it for your code by calling SetMAC on a match):
VOID EnumerateNetworkAdapters(VOID)
{
ULONG len = 0;
if (ERROR_BUFFER_OVERFLOW == GetAdaptersInfo(NULL, &len))
{
IP_ADAPTER_INFO *ipai;
ipai = malloc(len);
if (NO_ERROR == GetAdaptersInfo(ipai, &len))
{
IP_ADAPTER_INFO *p = ipai;
do
{
printf("name=%s description=%s\n", p->AdapterName, p->Description);
}
while (p = p->Next);
}
free(ipai);
}
}
Link against "Iphlpapi.lib".
Use GetAdaptersAddresses to get the adapter name(PIP_ADAPTER_ADDRESSES::FriendlyName) by comparing the description(PIP_ADAPTER_ADDRESSES::Description) before the call to SetMAC(). Example can be found in above MSDN link.