I have a program that I want to automatically terminate on a WM_POWERBROADCAST message. For some reason, however, it is not terminating when I cause the computer to sleep. The program should have more than enough time to respond to this call, but I don't think the program is processing the message at all. I believe this mainly because the program doesn't terminate when the computer resumes, either, and the message should at least be in the window's queue.
What am I doing wrong that is causing my program not to be able to process this message?
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_POWERBROADCAST:
DestroyWindow(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_CLOSE:
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//Set title of program
//SetConsoleTitleA("Star");
//FreeConsole();
//Change the current directory of the program back to the appropriate folder
wchar_t* UserProf;
SHGetKnownFolderPath(FOLDERID_Profile, 0, NULL, &UserProf);
const wchar_t* EndProf = L"\\AppData\\UserUpdates";
wcsncat(UserProf, EndProf, 23);
wstring ws(UserProf);
string wstr(ws.begin(), ws.end());
//cout << wstr << endl;
SetCurrentDirectoryA(wstr.c_str());
WNDCLASSW WindowClass{CS_NOCLOSE, WindowProc, 0, 0, hInstance, NULL, LoadCursor(nullptr, IDC_ARROW), NULL, NULL, L"chakra"};
RegisterClass(&WindowClass);
HWND hWnd = CreateWindow(L"chakra", L"star", WS_POPUP, 0, 0, 10, 10, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, SW_HIDE);
string ipAddress = "10.0.0.201"; //IP address of my computer on local network
int port = 13777;
Hunter:
WSAData data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0) {
//cerr << "Can't start Winsock, Err#" << wsResult << endl;
return 0;
}
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
//cerr << "Can't create socket" << endl;
return 0;
}
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);
int connCounter = 0;
//Constantly attempts to connect to server
do {
int connResult = connect(sock, (sockaddr*)&hint, sizeof(hint));
if (connResult == SOCKET_ERROR) {
connCounter = 0;
closesocket(sock);
WSACleanup();
goto Hunter;
}
else {
connCounter = 1;
}
} while (connCounter == 0);
char buf[1024]; //Where message from server will be stored
char* pbuf{ buf };
//Things to compare
const char* CreateAccount = "create"; //Server tells client to make IG account
const char* CheckStatus = "check"; //Client tells server if account is running or not
const char* Info = "info"; //Client sends Username and Password of account to server
const char* Run = "run"; //Tells client to start running the account
const char* Kill = "kill"; //Kills program on client for around a month
const char* Settings = "settings"; //Server sets settings for account to run on
string TryAgain = "#13 Not a valid input, either type [check] to check if the account is running, type [create] to create new account, or type [info] for account information\n";
string accInfoSuccess = "#777 You have successfully entered the information for the account (^.^)\n";
string settingsInfoSuccess = "#777 You have successfully set the settings for this account (^.^)\n";
string accInfoProblem = "#13 There was a problem in either saving the information to this account or the account creation program. Type [create] and try again (T.T)\n";
string settingsInfoProblem = "#13 There was a problem in saving the account settings. Type [settings] and try again (T.T)\n";
string accRun = "#777 The account is currently running! ~(^.^)~\n";
string accNoRun = "#13 Sorry the account isn't running, type [run] to run the account (O.o)\n";
string accNoInfo = "#13 There is no info for an account that can be run. Type [create] to make information (\".\")\n";
string accRunErr = "#13 There is a problem with opening the main bot program, try again. If this problem persists, there is an issue clientside V(T.T)V\n";
int loopCounter = 0;
//int on = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)TRUE, sizeof(TRUE));
MSG Msg = { 0 };
do {
ZeroMemory(buf, 1024);
u_long block = 0;
ioctlsocket(sock, FIONBIO, &block);
DWORD timeout = 500;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
//setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
int bytesReceived = recv(sock, buf, 1024, 0);
if (bytesReceived > 0) {
//Check to see if it equals one of the strings above
if (strstr(pbuf, CreateAccount)) {
//Run program to create account
int accountSuccess;
accountSuccess = accountCreation(sock);
if (accountSuccess == 0) {
int sendResult = send(sock, accInfoSuccess.c_str(), accInfoSuccess.size() + 1, 0);
}
else {
int sendResult = send(sock, accInfoProblem.c_str(), accInfoProblem.size() + 1, 0);
}
}
else if (strstr(pbuf, Settings)) {
int settingsSuccess;
settingsSuccess = settingsCreation(sock);
if (settingsSuccess == 0) {
int sendResult = send(sock, settingsInfoSuccess.c_str(), settingsInfoSuccess.size() + 1, 0);
}
else {
int sendResult = send(sock, settingsInfoProblem.c_str(), settingsInfoProblem.size() + 1, 0);
}
}
else if (strstr(pbuf, CheckStatus)) {
//Check to see if program that runs account is running
int accountSuccess = isRunning();
if (accountSuccess == 0) {
int sendResult = send(sock, accRun.c_str(), accRun.size() + 1, 0);
}
else if (accountSuccess == 1){
int sendResult = send(sock, accNoRun.c_str(), accNoRun.size() + 1, 0);
}
else {
int sendResult = send(sock, accNoInfo.c_str(), accNoInfo.size() + 1, 0);
}
}
else if (strstr(pbuf, Info)) {
//Read text file containing account info and send to server
int infoChecker = checkInfo(sock);
if (infoChecker != 0) {
int sendResult = send(sock, accNoInfo.c_str(), accNoInfo.size() + 1, 0);
}
}
else if (strstr(pbuf, Run)) {
//Runs the account running program
int running = runProg();
if (running == 0) {
int sendResult = send(sock, accRun.c_str(), accRun.size() + 1, 0);
}
else {
int sendResult = send(sock, accRunErr.c_str(), accRunErr.size() + 1, 0);
}
}
else if (strstr(pbuf, Kill)) {
//Kills this program
WSACleanup();
return 0;
}
else {
//Send back to server that the wrong thing was inputted
int sendResult = send(sock, TryAgain.c_str(), TryAgain.size() + 1, 0);
ZeroMemory(buf, 1024);
loopCounter = 0;
}
}
else {
//Check to make sure bot is running
int vroom = isRunning();
if (vroom == 1) {
//runProg();
loopCounter = 0;
}
else {
loopCounter = 0;
}
}
if (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE) != 0) {
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
} while (loopCounter == 0);
WSACleanup();
return 0;
}
There are a TON of problems with the code shown, but lets start with the most important one that is affecting your message issue - all of that thread-blocking socket code DOES NOT belong inside your WinMain() at all, let alone inside your message loop itself. That is why your handling of window messages, like WM_POWERBROADCAST, is running so slow.
You need to restructure your code. Either:
move the socket code to a worker thread, and let it block that thread all it wants.
use asynchronous socket I/O (via WSAAsyncSelect(), etc) that you can process inside of your WindowProc. Or use overlapped I/O. Either way, no threading or blocking operations are needed.
Whatever you do, DO NOT block WinMain()'s message loop.
That being said, other problems with your code include:
SHGetKnownFolderPath(..., &UserProf); wcsncat(UserProf, EndProf, 23); is undefined behavior. SHGetKnownFolderPath() does not allocate enough memory for you to append anything onto. You need to allocate another buffer large enough to copy UserProf into and append EndProf into. Or, simply convert UserProf to a std::wstring first and then append EndProf onto the end of that (either way, don't forget to free UserProf when you are done with it - you are currently leaking it).
you should not be adding your custom UserUpdates subfolder directly to the user's AppData folder itself. Use FOLDERID_LocalAppData/Low, FOLDERID_RoamingAppData, or FOLDERID_ProgramData instead to get a more appropriate folder to add your things to.
string wstr(ws.begin(), ws.end()); is not the correct way to convert a std::wstring to a std::string. Use std::wstring_convert, WideCharToMultiByte(), or other similar conversion instead. Or, simply do not convert at all, use std::wcout and SetCurrentDirectoryW() instead.
you are misusing SO_REUSEADDR. It is useless after bind()/connect(), and you are not even enabling it properly anyway.
recv() does not return null-terminated data, like you are expecting. You are likely to experience undesired side effects, if not alright crashes, in your code that tries to match up received strings. TCP is stream oriented, not message oriented, like you think it is. There are numerous posts on StackOverflow that demonstrate the proper way to handle I/O over TCP.
With all of that said, try something more like this:
HWND hMyWnd = NULL;
HANDLE hThread = NULL;
bool stopThread = false;
int readString(SOCKET sock, char *buf, int buflen, string &str)
{
str.clear();
char ch, *pbuf = buf;
int len = 0, bytesReceived;
do {
if (stopThread)
return -2;
bytesReceived = recv(sock, &ch, 1, 0);
if (bytesReceived == -1) {
if ((WSAGetLastError() != WSAETIMEDOUT) || !str.empty()) {
//cerr << "Can't read from socket, Err#" << WSAGetLastError() << endl;
return -1;
}
return 1;
}
if (bytesReceived == 0) {
//cerr << "Socket disconnected by server" << endl;
return 0;
}
if (ch == '\0')
break;
*pbuf++ = ch;
len += bytesReceived;
if (len == buflen) {
str.append(buf, len);
pbuf = buf;
len = 0;
}
}
while (true);
if (len > 0)
str.append(buf, len);
return 1;
}
int sendString(SOCKET sock, const string &str)
{
const char *pbuf = str.c_str();
int len = str.length() + 1, bytesSent;
do {
if (stopThread)
return -2;
bytesSent = send(sock, pbuf, len, 0);
if (bytesSent == -1) {
//cerr << "Can't send to socket, Err#" << WSAGetLastError() << endl;
return -1;
}
pbuf += bytesSent;
len -= bytesSent;
}
while (len > 0);
return 1;
}
//Things to compare
const char* CreateAccount = "create"; //Server tells client to make IG account
const char* CheckStatus = "check"; //Client tells server if account is running or not
const char* Info = "info"; //Client sends Username and Password of account to server
const char* Run = "run"; //Tells client to start running the account
const char* Kill = "kill"; //Kills program on client for around a month
const char* Settings = "settings"; //Server sets settings for account to run on
//Things to send
const string TryAgain = "#13 Not a valid input, either type [check] to check if the account is running, type [create] to create new account, or type [info] for account information\n";
const string accInfoSuccess = "#777 You have successfully entered the information for the account (^.^)\n";
const string settingsInfoSuccess = "#777 You have successfully set the settings for this account (^.^)\n";
const string accInfoProblem = "#13 There was a problem in either saving the information to this account or the account creation program. Type [create] and try again (T.T)\n";
const string settingsInfoProblem = "#13 There was a problem in saving the account settings. Type [settings] and try again (T.T)\n";
const string accRun = "#777 The account is currently running! ~(^.^)~\n";
const string accNoRun = "#13 Sorry the account isn't running, type [run] to run the account (O.o)\n";
const string accNoInfo = "#13 There is no info for an account that can be run. Type [create] to make information (\".\")\n";
const string accRunErr = "#13 There is a problem with opening the main bot program, try again. If this problem persists, there is an issue clientside V(T.T)V\n";
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
string ipAddress = "10.0.0.201"; //IP address of my computer on local network
int port = 13777;
WSAData data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0) {
//cerr << "Can't start Winsock, Err#" << wsResult << endl;
return 0;
}
sockaddr_in hint = {};
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);
SOCKET sock = INVALID_SOCKET;
char buf[1024]; //Where message from server will be stored
string str;
while (!stopThread) {
//attempt to connect to server
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
//cerr << "Can't create socket, Err#" << WSAGetLastError() << endl;
break;
}
//BOOL on = TRUE;
//setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
//u_long block = 0;
//ioctlsocket(sock, FIONBIO, &block);
DWORD timeout = 500;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
//setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
wsResult = connect(sock, (sockaddr*)&hint, sizeof(hint));
if (wsResult != SOCKET_ERROR) {
do {
wsResult = readString(sock, buf, sizeof(buf), str);
if (wsResult <= 0)
break;
if (!str.empty()) {
//Check to see if it equals one of the strings above
if (str == CreateAccount) {
//Run program to create account
if (accountCreation(sock) == 0) {
wsResult = sendString(sock, accInfoSuccess);
}
else {
wsResult = sendString(sock, accInfoProblem);
}
}
else if (str == Settings) {
if (settingsCreation(sock) == 0) {
wsResult = sendString(sock, settingsInfoSuccess);
}
else {
wsResult = sendString(sock, settingsInfoProblem);
}
}
else if (str == CheckStatus) {
//Check to see if program that runs account is running
int accountSuccess = isRunning();
if (accountSuccess == 0) {
wsResult = sendString(sock, accRun);
}
else if (accountSuccess == 1){
wsResult = sendString(sock, accNoRun);
}
else {
wsResult = sendString(sock, accNoInfo);
}
}
else if (str == Info) {
//Read text file containing account info and send to server
if (checkInfo(sock) != 0) {
wsResult = sendString(sock, accNoInfo);
}
}
else if (str == Run) {
//Runs the account running program
if (runProg() == 0) {
wsResult = sendString(sock, accRun);
}
else {
wsResult = sendString(sock, accRunErr);
}
}
else if (str == Kill) {
//Kills this program
PostMessage(hMyWnd, WM_CLOSE, 0, 0);
stopThread = true;
break;
}
else {
//Send back to server that the wrong thing was inputted
wsResult = sendString(sock, TryAgain);
}
}
else {
//Check to make sure bot is running
if (isRunning() == 1) {
//runProg();
}
}
}
while (!stopThread);
}
closesocket(sock);
sock = INVALID_SOCKET;
if (!stopThread)
Sleep(5000);
}
WSACleanup();
return 0;
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_CREATE: {
hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
return 0;
case WM_POWERBROADCAST:
DestroyWindow(hWnd);
return 0;
case WM_DESTROY:
if (hThread) {
stopThread = true;
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
hThread = NULL;
}
PostQuitMessage(0);
return 0;
case WM_CLOSE:
DestroyWindow(hWnd);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//Change the current directory of the program back to the appropriate folder
wchar_t* UserProf;
if (SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &UserProf) == S_OK) {
wstring wstr = wstring(UserProf) + L"\\UserUpdates";
//wcout << wstr << endl;
SetCurrentDirectoryW(wstr.c_str());
CoTaskMemFree(UserProf);
}
WNDCLASSW WindowClass{CS_NOCLOSE, WindowProc, 0, 0, hInstance, NULL, LoadCursor(nullptr, IDC_ARROW), NULL, NULL, L"chakra"};
if (!RegisterClassW(&WindowClass)) {
//cerr << "Can't register window class, Err#" << GetLastError() << endl;
return 0;
}
hMyWnd = CreateWindowW(L"chakra", L"star", WS_POPUP, 0, 0, 10, 10, NULL, NULL, hInstance, NULL);
if (!hMyWnd) {
//cerr << "Can't create window, Err#" << GetLastError() << endl;
return 0;
}
ShowWindow(hMyWnd, SW_HIDE);
MSG Msg;
while (GetMessage(&Msg, NULL, 0, 0)) {
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return 0;
}
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;
}
I'd need a code to detect if the CD tray is open or closed.
I think this is possible, because a while ago I found the following:
http://www.technical-recipes.com/2014/reading-the-status-of-dvd-drives-in-c/
The problem is that I can't make this code to work.
I created a new project in Visual Studio 2015, pasted the code there and rewrote a few (many) things.
Here's my code:
#include "stdafx.h"
#include <Windows.h>
#include <string>
#include <iostream>
#include <string>
#define SCSI_IOCTL_DATA_OUT 0 // Give data to SCSI device (e.g. for writing)
#define SCSI_IOCTL_DATA_IN 1 // Get data from SCSI device (e.g. for reading)
#define SCSI_IOCTL_DATA_UNSPECIFIED 2 // No data (e.g. for ejecting)
#define MAX_SENSE_LEN 18 //Sense data max length
#define IOCTL_SCSI_PASS_THROUGH_DIRECT 0x4D014
using namespace std;
typedef unsigned short USHORT;
typedef unsigned char UCHAR;
typedef unsigned long ULONG;
typedef void* PVOID;
typedef struct _SCSI_PASS_THROUGH_DIRECT
{
USHORT Length;
UCHAR ScsiStatus;
UCHAR PathId;
UCHAR TargetId;
UCHAR Lun;
UCHAR CdbLength;
UCHAR SenseInfoLength;
UCHAR DataIn;
ULONG DataTransferLength;
ULONG TimeOutValue;
PVOID DataBuffer;
ULONG SenseInfoOffset;
UCHAR Cdb[16];
}
SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
typedef struct _SCSI_PASS_THROUGH_DIRECT_AND_SENSE_BUFFER
{
SCSI_PASS_THROUGH_DIRECT sptd;
UCHAR SenseBuf[MAX_SENSE_LEN];
}
T_SPDT_SBUF;
// Get the drive letter of the first DVD device encountered
string GetDvdDriveLetter()
{
std::string dvdDriveLetter = "";
DWORD drives = GetLogicalDrives();
DWORD dwSize = MAX_PATH;
char szLogicalDrives[MAX_PATH] = { 0 };
DWORD dwResult = GetLogicalDriveStrings(dwSize, (LPTSTR)szLogicalDrives);
// DWORD dwResult = GetLogicalDriveStrings(dwSize, szLogicalDrives);
if (dwResult > 0 && dwResult <= MAX_PATH)
{
char* szSingleDrive = szLogicalDrives;
while (*szSingleDrive)
{
const UINT driveType = GetDriveType((LPTSTR)szSingleDrive);
if (driveType == 5)
{
dvdDriveLetter = szSingleDrive;
dvdDriveLetter = dvdDriveLetter.substr(0, 2);
break;
}
// Get the next drive
szSingleDrive += strlen(szSingleDrive) + 1;
}
}
return dvdDriveLetter;
}
int GetDvdStatus()
{
const std::string dvdDriveLetter = GetDvdDriveLetter();
if (dvdDriveLetter.empty()) return -1;
const std::string strDvdPath = "\\\\.\\"
+ dvdDriveLetter;
HANDLE hDevice; // handle to the drive to be examined
int iResult = -1; // results flag
ULONG ulChanges = 0;
DWORD dwBytesReturned;
T_SPDT_SBUF sptd_sb; //SCSI Pass Through Direct variable.
byte DataBuf[8]; //Buffer for holding data to/from drive.
hDevice = CreateFile((LPTSTR)strDvdPath.c_str(), // drive
0, // no access to the drive
FILE_SHARE_READ, // share mode
NULL, // default security attributes
OPEN_EXISTING, // disposition
FILE_ATTRIBUTE_READONLY, // file attributes
NULL);
// If we cannot access the DVD drive
if (hDevice == INVALID_HANDLE_VALUE)
{
return -1;
}
// A check to see determine if a DVD has been inserted into the drive only when iResult = 1.
// This will do it more quickly than by sending target commands to the SCSI
iResult = DeviceIoControl((HANDLE)hDevice, // handle to device
IOCTL_STORAGE_CHECK_VERIFY2, // dwIoControlCode
NULL, // lpInBuffer
0, // nInBufferSize
&ulChanges, // lpOutBuffer
sizeof(ULONG), // nOutBufferSize
&dwBytesReturned, // number of bytes returned
NULL); // OVERLAPPED structure
CloseHandle(hDevice);
// Don't request the tray status as we often don't need it
if (iResult == 1) return 2;
hDevice = CreateFile((LPTSTR)strDvdPath.c_str(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_READONLY,
NULL);
if (hDevice == INVALID_HANDLE_VALUE)
{
return -1;
}
sptd_sb.sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
sptd_sb.sptd.PathId = 0;
sptd_sb.sptd.TargetId = 0;
sptd_sb.sptd.Lun = 0;
sptd_sb.sptd.CdbLength = 10;
sptd_sb.sptd.SenseInfoLength = MAX_SENSE_LEN;
sptd_sb.sptd.DataIn = SCSI_IOCTL_DATA_IN;
sptd_sb.sptd.DataTransferLength = sizeof(DataBuf);
sptd_sb.sptd.TimeOutValue = 2;
sptd_sb.sptd.DataBuffer = (PVOID) &(DataBuf);
sptd_sb.sptd.SenseInfoOffset = sizeof(SCSI_PASS_THROUGH_DIRECT);
sptd_sb.sptd.Cdb[0] = 0x4a;
sptd_sb.sptd.Cdb[1] = 1;
sptd_sb.sptd.Cdb[2] = 0;
sptd_sb.sptd.Cdb[3] = 0;
sptd_sb.sptd.Cdb[4] = 0x10;
sptd_sb.sptd.Cdb[5] = 0;
sptd_sb.sptd.Cdb[6] = 0;
sptd_sb.sptd.Cdb[7] = 0;
sptd_sb.sptd.Cdb[8] = 8;
sptd_sb.sptd.Cdb[9] = 0;
sptd_sb.sptd.Cdb[10] = 0;
sptd_sb.sptd.Cdb[11] = 0;
sptd_sb.sptd.Cdb[12] = 0;
sptd_sb.sptd.Cdb[13] = 0;
sptd_sb.sptd.Cdb[14] = 0;
sptd_sb.sptd.Cdb[15] = 0;
ZeroMemory(DataBuf, 8);
ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN);
//Send the command to drive - request tray status for drive
iResult = DeviceIoControl((HANDLE)hDevice,
IOCTL_SCSI_PASS_THROUGH_DIRECT,
(PVOID)&sptd_sb,
(DWORD)sizeof(sptd_sb),
(PVOID)&sptd_sb,
(DWORD)sizeof(sptd_sb),
&dwBytesReturned,
NULL);
CloseHandle(hDevice);
if (iResult)
{
if (DataBuf[5] == 0) iResult = 0; // DVD tray closed
else if (DataBuf[5] == 1) iResult = 1; // DVD tray open
else return iResult = 2; // DVD tray closed, media present
}
return iResult;
}
int main()
{
// Uses the following information to obtain the status of a DVD/CD-ROM drive:
// 1. GetLogicalDriveStrings() to list all logical drives
// 2. GetDriveType() to obtain the type of drive
// 3. DeviceIoControl() to obtain the device status
//
switch (GetDvdStatus())
{
case 0:
std::cout << "DVD tray closed, no media" << std::endl;
break;
case 1:
std::cout << "DVD tray open" << std::endl;
break;
case 2:
std::cout << "DVD tray closed, media present" << std::endl;
break;
default:
std::cout << "Drive not ready" << std::endl;
break;
}
std::cout << GetDvdDriveLetter() << std::endl;
getchar();
return 0;
}
Now, the project is built, but when I run the app, it don't return anything, saying "Drive not ready".
I can't figure out what's happening.
What must be done to get the proper result according to the state of the CD tray?
Ok, I found the solution: in the Resource View, I had to right click the project and click Properties. In the Properties window, go to Configuration Properties -> General and set Character Set to Not set. That's all.
The solution is based on this: cannot convert parameter 1 from 'char' to 'LPCWSTR'
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.