Windows limit CPU usage using JobObject not working on all computers - c++

I am using JobObject to limit my process cpu usage. I am running my code on two computers running windows 10. On one machine it's working but on the other it's not working although all WINAPI calls return successfully. This my code:
string jobName = "test_job";
HANDLE hJobObject = NULL;
hJobObject = CreateJobObject(NULL, jobName.c_str());
if (hJobObject == NULL) {
return -1;
}
JOBOBJECT_CPU_RATE_CONTROL_INFORMATION cpuRateInfo;
cpuRateInfo.ControlFlags = JOB_OBJECT_CPU_RATE_CONTROL_ENABLE | JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP;
cpuRateInfo.CpuRate = 10 * 100;
if (!SetInformationJobObject(hJobObject, JobObjectCpuRateControlInformation, &cpuRateInfo, sizeof(JOBOBJECT_CPU_RATE_CONTROL_INFORMATION))) {
return -1;
}
HANDLE currentProcessHandle = GetCurrentProcess();
if (!AssignProcessToJobObject(hJobObject, currentProcessHandle)) {
return -1;
}
Any idea what cause this issue?

You should first verify that the current process works under an existing job control.
Add these lines of codeļ¼š
BOOL bInJob = FALSE;
IsProcessInJob(GetCurrentProcess(),NULL,&bInJob);
if (bInJob)
{
MessageBox(NULL,L"Process is in Job!",TEXT(""),MB_ICONINFORMATION | MB_OK);
return 0;
}
Since a process belongs to one job object, it cannot be assigned to another job object.
In addition, In Windows-enabled UAC systems, processes without
prompt privileges are added to a default compatibility system
JobObject, so a process must be created using the
CREATE_BREAKAWAY_FROM_JOB parameter to separate the process from the
default JobObject.
Hope to help you.

Related

WNetOpenEnum returns ERROR_NETWORK_UNREACHABLE for the "Microsoft Windows Network" node

Our program has a piece of code that calculates the list of computers on our local network. It uses the Windows Networking API (WNetOpenEnum/WNetEnumResource) to unwind the network. For many years, the resulting list was identical to the one that can be seen in Windows Explorer under the "Network" entry. However, recently we have noticed that the same code returns an empty list. During debugging I found that WNetOpenEnum returns error 1231 (ERROR_NETWORK_UNREACHABLE) when it is called for the "Microsoft Windows Network" under the root node.
I have to mention, though I'm pretty sure it has nothing to do with the matter, that the network unwinding is done multithreaded, to avoid possible delays in the main GUI thread. Each time a node of type RESOURCEUSAGE_CONTAINER is encountered, a new worker thread is launched. The thread function calls the following procedure:
DWORD WINAPI EnumNetwork(NETRESOURCE_M* lpNR)
{
const int BUF_SIZE = 16384; // 16K is a good size.
HANDLE hEnum;
DWORD Result;
// Call the WNetOpenEnum function to begin the enumeration.
Result = ::WNetOpenEnum(RESOURCE_GLOBALNET, // all network
RESOURCETYPE_ANY, // all resource types
0, // enumerate all
(LPNETRESOURCE)lpNR,// parent resource
&hEnum); // enumeration handle
if (Result != NO_ERROR) // -> for "Microsoft Windows Network" Result = 1231
return Result;
std::vector<std::wstring> SrvList;
// Allocate buffer for enumeration.
LPNETRESOURCE lpEnumNR = (LPNETRESOURCE)new char[BUF_SIZE];
if (lpEnumNR == 0)
Result = ERROR_OUTOFMEMORY;
else
{
while (1)
{
::ZeroMemory(lpEnumNR, BUF_SIZE); // Initialize the buffer.
DWORD NumEntries = -1; // Enumerate all entries.
DWORD BufSize = BUF_SIZE;
// Call WNetEnumResource to continue the enumeration.
Result = ::WNetEnumResource(hEnum, // enumeration handle
&NumEntries,// number of entries to enumerate
lpEnumNR, // array of resources to return
&BufSize); // buffer size
if (Result == NO_ERROR)
{
// If the call succeeds, loop through the array.
for (unsigned i = 0; i < NumEntries; ++i)
{
if (lpEnumNR[i].dwDisplayType == RESOURCEDISPLAYTYPE_SERVER)
{
// Collect servers.
LPCWSTR SrvName = lpEnumNR[i].lpRemoteName;
if (PathHelpers::IsFullPath(SrvName))
SrvList.push_back(SrvName);
}
else if ((lpEnumNR[i].dwUsage & RESOURCEUSAGE_CONTAINER) &&
lpEnumNR[i].lpRemoteName != 0)
{
TCHAR PathBuf[1024] = {0};
if (lpNR && lpNR->Path)
{
_tcscpy(PathBuf, lpNR->Path);
::PathAddBackslash(PathBuf);
}
_tcscat(PathBuf, lpEnumNR[i].lpRemoteName);
if (RegisterServer(PathBuf))
{
// Start new thread for recursive enumeration.
NETRESOURCE_M* lpChildNR = DeepCopyNR(&lpEnumNR[i], PathBuf);
ExploreNetwork(lpChildNR); // -> this starts a worker thread
}
else
{
GetLogger().LogMessage(
_T("Cycles found while unwinding network: %s"), PathBuf);
}
}
}
}
else
{
if (Result == ERROR_NO_MORE_ITEMS)
Result = NO_ERROR;
break;
}
} // end while
delete [] (char*)lpEnumNR;
} // end if
::WNetCloseEnum(hEnum);
if (!SrvList.empty())
NotifyServerAdded(SrvList);
return Result;
}
where NETRESOURCE_M is the structure
struct NETRESOURCE_M
{
NETRESOURCE NR;
LPTSTR Path;
};
Trying to figure out what could have caused such a sudden change in behavior, I found in Google that a few years ago Microsoft disabled the SMB1 protocol, which could affect Network Discovery. However, I can't believe they could have damaged their own API without saying a word in the documentation.
EDIT: At the same time, Windows Explorer has a bunch of computers under its "Network" node. In the network settings, the network type is "Domain", and the network discovery is ON. Services "Function Discovery Provider Host" and "Function Discovery Resources Publication" are running. Windows OS build is 19042.685.
Edit 2: The Sysinternals' "ShareEnum" tool also fails with the error: "No domains or workgroups where found on your network". Because of this, and also because some time ago our company moved all of its computers to a different network, I got the feeling that the problem is in the network configuration. Such as though the network is declared as "Domain", the computers were not enrolled to this domain. I do not understand much in that, but something like this.

Object pointer randomly points to 0x00000

I'm running a Visual C++ MFC application in release mode. I'm compiling everything using Visual Studio 2010.
My app runs a mini CNC mill through USB VCP communication.
I have a XML file that stores the app's settings.
My problem is this: ocassionaly (and this is repeatable) the pointer to the tinyxml2::XMLDocument I'm using gets set to 0x000.
Info:
Occasionally, the XML file get written to while the mill is running.
Before the error happens, the mill I'm running siezes for almost 30 seconds.
I'm using mutex locks to make sure the xmldoc doesn't get written to file twice at once.
The mutex locks are working, and the mutex error never occurs. I know the mutex code isn't perfect, but that isn't the issue. Honest.
I never write to the xmldoc pointer except when the parent class is booting up.
And then, all of a sudden, the xmlDoc pointer gets set to zero.
Any thoughts anyone?
Here is my saving code, although the problem may lie elsewhere:
void XMLSettings::SaveToXML()
{
HANDLE g_Mutex = CreateMutex( NULL, TRUE, "XMLSavingMutex");
DWORD wait_success = WaitForSingleObject( g_Mutex, 30000L);
if(wait_success == WAIT_OBJECT_0){
CIsoProApp* pApp = (CIsoProApp*)AfxGetApp();
if(PathFileExists(pApp->DrivePath + "IsoPro\\temp.xml"))
{
DeleteFile(pApp->DrivePath + "IsoPro\\temp.xml");
}
if(0==&xmlDoc)
{
OutputDebugString("xmlDoc == NULL");
}
int errorcode = xmlDoc->SaveFile(pApp->DrivePath + "IsoPro\\temp.xml");
if(errorcode != 0)
{
OutputDebugString("xmlDoc == errorcode");
}
if(0==&xmlDoc)
{
OutputDebugString("xmlDoc == NULL2");
}
if(0==xmlDoc)
{
OutputDebugString("xmlDoc == NULL");
}
if(PathFileExists(pApp->DrivePath + "IsoPro\\Settings.xml"))
{
DeleteFile(pApp->DrivePath + "IsoPro\\Settings.xml");
}
MoveFile(pApp->DrivePath + "IsoPro\\temp.xml",pApp->DrivePath + "IsoPro\\Settings.xml");
ReleaseMutex(g_Mutex);
}
else
{
int errorInt = GetLastError();
CString error;
error.Format("%d",errorInt);
if(errorInt != ERROR_ALREADY_EXISTS)
{
AfxMessageBox("XMLSavingMutex Error. WaitSuccess = " + wait_success);
AfxMessageBox("XMLSavingMutex Error. GetLastError = " + error);
}
}
CloseHandle(g_Mutex);
}
Since it seems that you are creating a Mutex each time SaveToXML is called, you should change your call to
HANDLE g_Mutex = CreateMutex( NULL, FALSE, "XMLSavingMutex");
Doing this will create a named mutex that allows the implementation to dictate who the owner is; other threads will receive the same mutex.
From the doc:
Two or more processes can call CreateMutex to create the same named mutex. The first process actually creates the mutex, and subsequent processes with sufficient access rights simply open a handle to the existing mutex. This enables multiple processes to get handles of the same mutex, while relieving the user of the responsibility of ensuring that the creating process is started first. When using this technique, you should set the bInitialOwner flag to FALSE; otherwise, it can be difficult to be certain which process has initial ownership.
(Credit to WhozCraig for pointing out named mutexes)
It appears that I was accessing the xml getter while writing the xml to a file. I put a single mutex lock in place for all xml actions and things seem to be functioning properly. Thanks to everyone for their help. I'll be in touch with more info if it becomes available.

Is there a way to detect if a monitor is plugged in?

I have a custom application written in C++ that controls the resolution and other settings on a monitor connected to an embedded system. Sometimes the system is booted headless and run via VNC, but can have a monitor plugged in later (post boot). If that happens he monitor is fed no video until the monitor is enabled. I have found calling "displayswitch /clone" brings the monitor up, but I need to know when the monitor is connected. I have a timer that runs every 5 seconds and looks for the monitor, but I need some API call that can tell me if the monitor is connected.
Here is a bit of psudocode to describe what I'm after (what is executed when the timer expires every 5 seconds).
if(If monitor connected)
{
ShellExecute("displayswitch.exe /clone);
}else
{
//Do Nothing
}
I have tried GetSystemMetrics(SM_CMONITORS) to return the number of monitors, but it returns 1 if the monitor is connected or not. Any other ideas?
Thanks!
Try the following code
BOOL IsDisplayConnected(int displayIndex = 0)
{
DISPLAY_DEVICE device;
device.cb = sizeof(DISPLAY_DEVICE);
return EnumDisplayDevices(NULL, displayIndex, &device, 0);
}
This will return true if Windows identifies a display device with index (AKA identity) 0 (this is what the display control panel uses internally). Otherwise, it will return false false. So by checking the first possible index (which I marked as the default argument), you can find out whether any display device is connected (or at least identified by Windows, which is essentially what you're looking for).
Seems that there is some kind of "default monitor" even if no real monitor is connected.
The function below works for me (tested on a Intel NUC and a Surface 5 tablet).
The idea is to get the device id and check if it contains the string "default_monitor".
bool hasMonitor()
{
// Check if we have a monitor
bool has = false;
// Iterate over all displays and check if we have a valid one.
// If the device ID contains the string default_monitor no monitor is attached.
DISPLAY_DEVICE dd;
dd.cb = sizeof(dd);
int deviceIndex = 0;
while (EnumDisplayDevices(0, deviceIndex, &dd, 0))
{
std::wstring deviceName = dd.DeviceName;
int monitorIndex = 0;
while (EnumDisplayDevices(deviceName.c_str(), monitorIndex, &dd, 0))
{
size_t len = _tcslen(dd.DeviceID);
for (size_t i = 0; i < len; ++i)
dd.DeviceID[i] = _totlower(dd.DeviceID[i]);
has = has || (len > 10 && _tcsstr(dd.DeviceID, L"default_monitor") == nullptr);
++monitorIndex;
}
++deviceIndex;
}
return has;
}

Why WNetAddConnection2 still returns 1219 after successfully calling WNetCancelConnection2?

I wrote some code to connect with some share on a remote server. If WNetAddConnection2 returns ERROR_SESSION_CREDENTIAL_CONFLICT (1219), I will first cancel the connection by WNetCancelConnection2 (return NO_ERROR). And then reconnect. But WNetAddConnection2 still returns 1219.
Why this and how to fix it?
Here's my code
BOOL ADDirectorySearch::IPCConnect(CString strServerName, CString strDomainName, CString strUserName, CString strPassWord)
{
CString strServerNameWithSlash = _T("\\\\") + strServerName; //actually is \\klbnt
CString strFullUserName = strDomainName + _T("\\") + strUserName; //is domaintest\administrator
_bstr_t bstrServerNameWithSlash = strServerNameWithSlash;
_bstr_t bstrFullUserName = strFullUserName;
_bstr_t bstrPassWord = strPassWord;
DWORD dwResult;
NETRESOURCEW netResource;
memset(&netResource, 0, sizeof(netResource));
netResource.dwScope = RESOURCE_GLOBALNET;
netResource.dwType = RESOURCETYPE_DISK;
netResource.dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
netResource.dwUsage = RESOURCEUSAGE_CONNECTABLE;
netResource.lpProvider = L"";
netResource.lpRemoteName = bstrServerNameWithSlash;//Remote IP like:\\192.168.1.11
dwResult = WNetAddConnection2W(&netResource, bstrPassWord, bstrFullUserName, CONNECT_INTERACTIVE);
if (dwResult == ERROR_SESSION_CREDENTIAL_CONFLICT)
{
dwResult = WNetCancelConnection2W(bstrServerNameWithSlash, CONNECT_UPDATE_PROFILE, TRUE);
if (dwResult == NO_ERROR)
{
dwResult = WNetAddConnection2W(&netResource, bstrPassWord, bstrFullUserName, CONNECT_INTERACTIVE);
}
else
{
//MyMessageBox_Error(_T("IPCConnect Error."), _T("Error"));
return FALSE;
}
}
if (dwResult == NO_ERROR)
{
return TRUE;
}
else
{
//MyMessageBox_Error(_T("IPCConnect Error."), _T("Error"));
return FALSE;
}
}
FYI: After typing "net use" in cmd, I got this, I feel there's something with error:
Status Local Remote Network
-------------------------------------------------------------------------------
OK \\klbnt\NRDC1001 Microsoft Windows Network
The command completed successfully.
I was just having this problem now, and basically it seemed that it was due to another process still having file open, even though I specified "true" as the last parameter of WNetCancelConnection2() to force close the connection. Once I shut-down that other process, I was able to use successfully switch between credentials connecting and re-connecting to the same share. This is on Windows 2012 (64-bit), and the share was local (referenced by the machinename).
BUT...it's still a problem if you want to connect to different shares on the same machine. If I try to connect to \\mymachine\share1 as user1 then to \\mymachine\share2 as user2, I get the 1219 error (even if it's in a completely different process). I have to explicitly call WNetCancelConnnection on \\mymachine\share1 before I can connect to share2, which means at the point you connect to a share on a particular machine, you may have to first enumerate existing connections and close each one.
Rather frustrating, and I can't understand the design principle here. It seems the flags to create temporary connections etc. have no effect on this behaviour either. Really what I want to be able to do is say "for this thread, connect to this share on this machine and as this user, such that all attempts to access files on the share are done with that user's credentials". That way what other processes/threads are doing can't cause issues with the current one.

How do I find out if a .exe is running in c++?

How can you find out if an executable is running on Windows given the process name, e.g. program.exe?
The C++ standard library has no such support. You need an operating system API to do this. If this is Windows then you'd use CreateToolhelp32Snapshot(), followed by Process32First and Process32Next to iterate the running processes. Beware of the inevitable race condition, the process could have exited by the time you found it.
I just created one using Hans suggestion. Works like a champ!
Oh and here is the basic code.
Please you will have to add CStrings sAppPath and sAppName.
StartProcess is a small function that uses CreateProcess and returns the PID(not used here). You will need to replace it.
This is not a complete program, just the code to find if the program is running using Hans suggestion. A fun test is to set the path to c:\windows\ and the app to notepad.exe and set it for 10 seconds.
#include <tlhelp32.h>
PROCESSENTRY32 pe32 = {0};
HANDLE hSnap;
int iDone;
int iTime = 60;
bool bProcessFound;
while(true) // go forever
{
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
pe32.dwSize = sizeof(PROCESSENTRY32);
Process32First(hSnap,&pe32); // Can throw away, never an actual app
bProcessFound = false; //init values
iDone = 1;
while(iDone) // go until out of Processes
{
iDone = Process32Next(hSnap,&pe32);
if (strcmp(pe32.szExeFile,sAppName) == 0) // Did we find our process?
{
bProcessFound = true;
iDone = 0;
}
}
if(!bProcessFound) // if we didn't find it running...
{
startProcess(sAppPath+sAppName,""); // start it
}
Sleep(iTime*1000); // delay x amount of seconds.
}
Assumptions: since you mention '.exe', you want this for some flavor of Windows. You want to write a program in C++ to determine whether a program with a particular executable name is running (regardless of the language used to implement the target program).
Enumerate the running processes using either the Toolhelp API or the process status API. Compare the name of the executable for each running process to the one you're looking for (and be aware that there may be more than one process with that executable name).
hProcessInfo = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );
do{
if(strcmp(pe32.szExeFile,"process.exe") == 0)
{
processfound = true;
break;
}
}while( Process32Next( hProcessSnap, &pe32 ) );
If you don't want to get process detail from code just press Ctrl+Alt+Del and check process list.