I'm trying to set wcm_global_property_minimize_policy through the WcmSetProperty API. For some reason, the call returns error 87 (Invalid Parameter). The strange thing is I can query this policy through WcmQueryProperty successfully. I have tried to find sample code in the Windows 8 SDK, but AFAIL there are no samples that change global properties.
Can someone tell me what I'm doing wrong in the following code?
void __cdecl main()
{
DWORD dwRetCode = NO_ERROR;
DWORD dwSize = 0;
WCM_POLICY_VALUE policyVal;
WCM_POLICY_VALUE *outVal;
/* Disable Minimize Connections */
policyVal.fIsGroupPolicy = false;
policyVal.fValue = false;
dwSize = sizeof(policyVal);
wprintf(L"Disabling global property - minimize connections... dwSize: %u\n", dwSize);
dwRetCode = WcmSetProperty(NULL, NULL, wcm_global_property_minimize_policy, NULL, dwSize, (PBYTE)&policyVal);
if (dwRetCode == ERROR_SUCCESS) {
wprintf(L"Disable global property minimize connections is success\n");
}
else {
wprintf(L"Disable global property minimize connections failed\n");
wprintf(L"Error code: %u\n", dwRetCode);
}
dwRetCode = WcmQueryProperty(NULL, NULL, wcm_global_property_minimize_policy, NULL, &dwSize, (PBYTE *)&outVal);
if ((dwRetCode == ERROR_SUCCESS) /*&& (p2Data != NULL)*/) {
wprintf(L"Global property minimize policy is: %d.%d with size %d\n", outVal->fIsGroupPolicy, outVal->fValue, dwSize);
}
else {
wprintf(L"Error in querying property - minimize policy \n");
wprintf(L"Error code: %u\n", dwRetCode);
}
}
Also, if I change wcm_global_property_minimize_policy through WcmSetProperty (), will this require a system reboot before the changed setting goes into effect?
Thanks!
Here's a response from an MSDN forum:
"When calling WcmSetProperty, the documentation specifies that the type of data stored in the pbData should be WCM_POLICY_VALUE.
This appears to be an error in the documentation. For setting wcm_global_property_minimize_policy, set pbData as type BOOL and the call should succeed."
Related
I am trying to inject a dll I've made into note pad.
I've written the following code where I open a process of notepad and inject it with my dll.
Yet, for some reason, my virtualalloc fails.
Would really appreciate some help on the matter.
Code:
#include <Windows.h>
#include <stdio.h>
int main()
{
char dllPath[125];
DWORD pathLen = GetFullPathNameA("MagshimimFinalProject.dll" ,160 , dllPath, NULL);
PVOID addrLoadLibrary = (PVOID)GetProcAddress(GetModuleHandle("notepad.exe"), "LoadLibraryA"); // maybee we need text instead of the dllpath
HANDLE proc = OpenProcess("PROCESS_CREATE_PROCESS",FALSE, "6340");
PVOID memAddr = (PVOID)VirtualAllocEx(proc, NULL,pathLen,MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (NULL == memAddr)
{
printf("Couldn't allocate memory");
DWORD err = GetLastError();
return 0;
}
HANDLE hRemote = CreateRemoteThread(proc,NULL,0,memAddr, NULL,0,NULL );
if (NULL == hRemote)
{
printf("Couldn't create thread");
DWORD err = GetLastError();
return 0;
}
WaitForSingleObject(hRemote, INFINITE);
BOOL check = CloseHandle(hRemote);
return 0;
}
I've tried looking up all of the functions and making sure they are all getting the right variables, and looking up tutorials on the matter on youtube, but to no avail.
Edit - as the first comment suggested, I've used the debugger to look at each and every line, and when I checked addrLoadLibrary its value was: "identifier "addrLoadLibrary" is undefined" for some reason. any clue why that is?
Edit 2 - firstly, I was checking its value after the line has been completed (value of addrloadlibrary). Secondly, as someone has mentioned, proc is actually the problem for some reason, as its always NULL. Still trying to figure out why is it not working
edit 3 - fixed the problem with proc by removing the quotation marks like some guy in the comments was telling me (sorry for not remembering name, I'm very bad at that.) Now all thats left to figure out is why is addrLoadLibrary undefined even after line
edit 4 - re-read the documentation of the function "getModuleHandle" and relized it should get the dllpath variable. hopefully im not wrong because im not a native english speaker and documentations are especially tough for me to understand.
There are tons of things wrong with this code. Most of the API calls are just plain incorrect. You are not doing very much error checking. You are not copying the DLL path into the memory you allocate before creating the remote thread.
Try something more like this instead:
#include <Windows.h>
#include <stdio.h>
int main() {
char dllPath[MAX_PATH];
DWORD pathLen = GetFullPathNameA("MagshimimFinalProject.dll", MAX_PATH, dllPath, NULL);
if (!pathLen) {
DWORD err = GetLastError();
printf("Couldn't get DLL path. Error: %u", err);
return 0;
}
PVOID addrLoadLibrary = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
// TODO: use CreateToolhelp32Snapshot() or EnumProcesses() to find the correct process ID...
DWORD procID = 6340;
HANDLE proc = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, procID);
if (!proc) {
DWORD err = GetLastError();
printf("Couldn't open process. Error: %u", err);
return 0;
}
PVOID memAddr = VirtualAllocEx(proc, NULL, pathLen+1, MEM_COMMIT, PAGE_READWRITE);
if (!memAddr) {
DWORD err = GetLastError();
CloseHandle(proc);
printf("Couldn't allocate memory. Error: %u", err);
return 0;
}
if (!WriteProcessMemory(proc, memAddr, dllPath, pathLen+1, NULL)) {
DWORD err = GetLastError();
VirtualFreeEx(proc, memAddr, 0, MEM_RELEASE);
CloseHandle(proc);
printf("Couldn't write to memory. Error: %u", err);
return 0;
}
HANDLE hRemote = CreateRemoteThread(proc, NULL, 0, addrLoadLibrary, memAddr, 0, NULL);
if (!hRemote) {
DWORD err = GetLastError();
VirtualFreeEx(proc, memAddr, 0, MEM_RELEASE);
CloseHandle(proc);
printf("Couldn't create thread. Error: %u", err);
return 0;
}
WaitForSingleObject(hRemote, INFINITE);
CloseHandle(hRemote);
VirtualFreeEx(proc, memAddr, 0, MEM_RELEASE);
CloseHandle(proc);
return 0;
}
I'm currently writing a Windows service, which also does something when a user logs on. There was the idea to do nothing if the logon comes from a remote computer (e.g. Remote desktop), and tried to find a way to dermine this. But following does not work - it always returns true (Windows 10 64 bit V1809) - is there something I doing wrong here?
DWORD SvcHandlerEx(DWORD controlCode, DWORD eventType, ... )
{
...
switch(controlCode)
{
case SERVICE_CONTROL_SESSIONCHANGE:
{
WTSSESSION_NOTIFICATION *pSessInfo = (WTSSESSION_NOTIFICATION *)pEvtData;
// invoke SessionChangeHandler(eventId, pSessInfo->dwSessionId)
}
...
}
...
}
...
VOID SessionChangeHandler(DWORD reason, DWORD sessionId)
{
LPWSTR *pSessionInfo = nullptr;
DWORD dataLen = 0;
BOOL isRDP = false;
if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId,
WTSIsRemoteSession, &pSessionInfo, &dataLen))
{
// Do some error handling...
return;
}
if (dataLen)
{
if (dataLen)
{
isRDP = (bool)pSessionInfo; // Always 1 (TRUE) !!!
}
WTSFreeMemory(pSessionInfo);
}
...
}
Per the documentation for WTSIsRemoteSession:
WTSIsRemoteSession
Determines whether the current session is a remote session.
The WTSQuerySessionInformation function returns a value of TRUE to indicate that the current session is a remote session, and FALSE to indicate that the current session is a local session. This value can only be used for the local machine, so the hServer parameter of the WTSQuerySessionInformation function must contain WTS_CURRENT_SERVER_HANDLE.
Windows Server 2008 and Windows Vista: This value is not supported.
This implies that the return value of WTSQuerySessionInformation() holds the value you are looking for, and whatever memory the function may allocate, if any, is secondary and should be ignored when querying WTSIsRemoteSession, eg:
VOID SessionChangeHandler(DWORD reason, DWORD sessionId)
{
LPWSTR *pSessionInfo = nullptr;
DWORD dataLen = 0;
bool isRDP = WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSIsRemoteSession, &pSessionInfo, &dataLen);
if ((!isRDP) && (GetLastError() != 0))
{
// Do some error handling...
return;
}
if (pSessionInfo)
WTSFreeMemory(pSessionInfo);
// use isRDP as needed...
...
}
However, if you find that isRDP is always true in this case, then the documentation is misleading and you should check the contents of the pSessionInfo buffer instead. You are setting your isRDP variable based on whether WTSQuerySessionInformation() allocates any memory at all, you are not looking at what is actually inside the data.
For instance, assuming dataLen is being set to sizeof(BOOL) on output then cast your pSessionInfo pointer to a BOOL* pointer and dereference it, eg:
VOID SessionChangeHandler(DWORD reason, DWORD sessionId)
{
LPWSTR *pSessionInfo = nullptr;
DWORD dataLen = 0;
if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSIsRemoteSession, &pSessionInfo, &dataLen))
{
// Do some error handling...
return;
}
bool isRDP = * (BOOL*) pSessionInfo;
WTSFreeMemory(pSessionInfo);
// use isRDP as needed...
...
}
Alternatively:
VOID SessionChangeHandler(DWORD reason, DWORD sessionId)
{
BOOL *isRDP = nullptr;
DWORD dataLen = 0;
if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSIsRemoteSession, (LPWSTR*)&isRDP, &dataLen))
{
// Do some error handling...
return;
}
// use isRDP as needed...
WTSFreeMemory(isRDP);
...
}
I have a printer connected that doesn't have a driver and doesn't show up under printers, but it shows up under "Start->Settings->Bluetooth & other devices" with name "SRP300".
I can send data to the printer via the following routine (found here : https://www.levelextreme.com/ViewPageGenericLogin.aspx?LoadContainer=1&NoThread=1157607 ) where it gets the Device Instance ID, and Guid - but I'm simply not able to figure out where I am to get the name from "SP300".
What would I need to call as soon as I've found the GUID of it? The best would be if I could search for the name to start with and if SP300 is found then get the instance id/guid, but I've tried different approaches enumerating to get that name that is shown but nothing seem to produce it.
If I inspect the registry I can see that it's grouped under USB and then under a folder called USBPRINT and then a folder 00000001 and in there there is the name, but wonder how I'm able to retrieve this with Win api calls?
int test2()
{
int MemberIndex = 0;
LONG Result = 0;
DWORD Length = 0;
HANDLE hDevInfo;
ULONG Required;
HANDLE m_hComm=NULL;
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL;
SP_DEVICE_INTERFACE_DATA devInfoData;
hDevInfo = SetupDiGetClassDevs((LPGUID)&(USB_PRINT), NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
printf("No hardware device");
return 0;
}
devInfoData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
//Step through the available devices looking for the one we want.
do
{
//[1]
Result = SetupDiEnumDeviceInterfaces(hDevInfo, 0, (LPGUID)&(USB_PRINT), MemberIndex, &devInfoData);
if (Result != 0)
{
SetupDiGetDeviceInterfaceDetail(hDevInfo, &devInfoData, NULL, 0, &Length, NULL);
//Allocate memory for the hDevInfo structure, using the returned Length.
detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)new BYTE[Length * 4];
//Set cbSize in the detailData structure.
detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
//Call the function again, this time passing it the returned buffer size.
if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &devInfoData, detailData, Length, &Required, NULL) == TRUE)
{
m_hComm = CreateFile(detailData->DevicePath,
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING, 0, NULL);
if (m_hComm != INVALID_HANDLE_VALUE)
{
//Result = 0;
printf("USB port Available");
}
CloseHandle(m_hComm);
}
delete(detailData);
}
MemberIndex = MemberIndex + 1;
} while (Result != 0);
SetupDiDestroyDeviceInfoList(hDevInfo);
printf("%u\r\n", MemberIndex);
;
return 0;
}
If an enumeration parameter value is not used to select devices, set Enumerator to NULL and when Enumerator is NULL, SetupDiGetClassDevs returns devices for all PnP enumerators. You could set this parameter either be the value's globally unique identifier (GUID) or symbolic name.
For more information, you could refer to this document below.
https://learn.microsoft.com/en-us/windows/desktop/api/setupapi/nf-setupapi-setupdigetclassdevsw
Best Regards,
Baron Bi
I want to obtain a monitor handle (HMONITOR) that can be used with the Windows multi-monitor APIs for a specific monitor attached to the system by index. For example, say I have three monitors attached to my system and forming part of my desktop; I want to get a handle to monitor 3.
I already know how to get the device name for a specific monitor by index by calling the EnumDisplayDevices function. For example:
HMONITOR MonitorFromIndex(int index /* (zero-indexed) */)
{
DISPLAY_DEVICE dd;
dd.cb = sizeof(dd);
if (EnumDisplayDevices(NULL, index, &dd, 0) != FALSE)
{
// We found a match; make sure that it's part of the desktop.
if ((dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) == DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)
{
// Yup. Now we've got the name of the device:
std::cout << dd.DeviceName << std::endl;
// But how do I obtain an HMONITOR for this device?
// ...
}
}
return NULL; // indicate failure
}
In the code above, we've found the name of the desired device (dd.DeviceName). I can use this name to create a DC for that monitor by calling CreateDC:
HDC hDC = CreateDC(dd.DeviceName, dd.DeviceName, NULL, NULL);
And I can obtain information about that monitor by calling EnumDisplaySettings:
DEVMODE dm;
dm.dmSize = sizeof(dm);
dm.dmDriverExtra = 0;
if (EnumDisplaySettings(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm) != FALSE)
{
std::cout << "The monitor supports " << dm.dmBitsPerPel << " bits per pixel." << std::endl;
}
Which is all great, but I want a handle to that monitor. How can I get it?
I tried to call EnumDisplayMonitors, passing a handle to the device context that I created using CreateDC, hoping to get a handle to the monitor passed to the callback function, but no such luck. The callback function was never called, and EnumDisplayMonitors returned FALSE (without setting an error code):
struct FoundMatch
{
BOOL found;
HMONITOR hMonitor;
};
BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData)
{
FoundMatch* pfm = reinterpret_cast<FoundMatch*>(dwData);
pfm->found = TRUE;
pfm->hMonitor = hMonitor;
return FALSE; // stop enumerating
}
// elsewhere, after getting the device name and using it to create a DC
FoundMatch fm;
fm.found = FALSE;
fm.hMonitor = NULL;
BOOL result = EnumDisplayMonitors(hDC, NULL, MonitorEnumProc, reinterpret_cast<LPARAM>(&fm));
Sorry for such a late reply but maybe someone can find this useful.
The multi-monitor API is really minimalist to say the least. Once you've got your dd.DeviceName, it appears you have to go through EnumDisplayMonitors() enumeration until you find a match of dd.DeviceName against MONITORINFOEX.szDevice.
The MONITORINFOEX structure can be obtained by calling GetMonitorInfo().
Here is a non-compilable C++11 pseudo code:
struct DataBag
{
HMONITOR hmon;
TCHAR* devname;
} bag;
bag.hmon = NULL;
bag.devname = &dd.DeviceName;
BOOL bRes = EnumDisplayMonitors(
NULL, NULL,
[](HMONITOR hMonitor, HDC hDC, LPRECT rc, LPARAM data) -> BOOL {
auto& bag = *reinterpret_cast<DataBag*>(data);
MONITORINFOEX mi;
mi.cbSize = sizeof(mi);
if (/* match bag.devname against mi.szDevice */ && GetMonitorInfo(hMonitor, &mi))
{
bag.hmon = hMonitor;
return FALSE;
}
return TRUE;
},
reinterpret_cast<LPARAM>(&bag));
if (bRes && bag.hmon)
{
// Monitor found!
}
Can anyone Please tell me how to get Model name of Windows Machine.
I am new to Windows VC++.
For Example i have an IBM ThinkCenter M50 running on Windows. Here the Model name is "Think Center M50". I want to get this from the System using some API.
Thanks in Advance,
Shashi Kiran G M
Alternatively, you could use the registry key:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SystemInformation
also: HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\BIOS (Win7 or later only)
The SystemManufacturer and SystemProductName entries should do it. Saves using WMI, which i try to avoid at all costs for performance reasons.
As Ben suggests, you'll need to use WMI for this.
The class you're looking for is Win32_ComputerSystem, which contains a read-only Model property of type string that returns the product name that a manufacturer gives to a computer.
I'll leave writing the C++ code to make this WMI call as an exercise for the reader.
Do note Ben's caveat as well: not all manufacturers publish this information in the BIOS. It's very likely that IBM does, so your test case should work out fine, but this is not a universal assumption that you are justified in making. Applications should not rely on this property containing a particular value.
With the help of the Microsoft example code, I was able to create this method.
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
std::pair<CString,CString> getComputerManufacturerAndModel() {
// Obtain the initial locator to Windows Management on a particular host computer.
IWbemLocator *locator = nullptr;
IWbemServices *services = nullptr;
auto hResult = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&locator);
auto hasFailed = [&hResult]() {
if (FAILED(hResult)) {
auto error = _com_error(hResult);
TRACE(error.ErrorMessage());
TRACE(error.Description().Detach());
return true;
}
return false;
};
auto getValue = [&hResult, &hasFailed](IWbemClassObject *classObject, LPCWSTR property) {
CString propertyValueText = "Not set";
VARIANT propertyValue;
hResult = classObject->Get(property, 0, &propertyValue, 0, 0);
if (!hasFailed()) {
if ((propertyValue.vt == VT_NULL) || (propertyValue.vt == VT_EMPTY)) {
} else if (propertyValue.vt & VT_ARRAY) {
propertyValueText = "Unknown"; //Array types not supported
} else {
propertyValueText = propertyValue.bstrVal;
}
}
VariantClear(&propertyValue);
return propertyValueText;
};
CString manufacturer = "Not set";
CString model = "Not set";
if (!hasFailed()) {
// Connect to the root\cimv2 namespace with the current user and obtain pointer pSvc to make IWbemServices calls.
hResult = locator->ConnectServer(L"ROOT\\CIMV2", nullptr, nullptr, 0, NULL, 0, 0, &services);
if (!hasFailed()) {
// Set the IWbemServices proxy so that impersonation of the user (client) occurs.
hResult = CoSetProxyBlanket(services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE);
if (!hasFailed()) {
IEnumWbemClassObject* classObjectEnumerator = nullptr;
hResult = services->ExecQuery(L"WQL", L"SELECT * FROM Win32_ComputerSystem", WBEM_FLAG_FORWARD_ONLY |
WBEM_FLAG_RETURN_IMMEDIATELY, nullptr, &classObjectEnumerator);
if (!hasFailed()) {
IWbemClassObject *classObject;
ULONG uReturn = 0;
hResult = classObjectEnumerator->Next(WBEM_INFINITE, 1, &classObject, &uReturn);
if (uReturn != 0) {
manufacturer = getValue(classObject, (LPCWSTR)L"Manufacturer");
model = getValue(classObject, (LPCWSTR)L"Model");
}
classObject->Release();
}
classObjectEnumerator->Release();
}
}
}
if (locator) {
locator->Release();
}
if (services) {
services->Release();
}
CoUninitialize();
return { manufacturer, model };
}