I need to check if the power of a display/monitor (is it ON or OFF ?).
I've tried with WMI, using the Win32_DesktopMonitor and check the "Availability", but the value returned is always 3 (powered on), even when the monitor is physically turned off.
Now, looking at a few threads here on StackOverflow, there's one direction I'd like to follow and it's the use of IMSVidDevice Interface, but I have no clue how to use it.
I have this link http://msdn.microsoft.com/en-us/library/windows/desktop/dd694527(v=vs.85).aspx to start.
It talks about using segment.h and segment.idl. There's also the mention of msvidctl.h.
I found an MS Video Control 1.0 Type Library which seems to be what I'm looking for (it has an IMSVidDevice interface defined) but I can't figure out how to use this library.
var devices = new MSVidCtlLib.MSVidOutputDevices();
Console.WriteLine("Found {0} devices", devices.Count);
foreach (MSVidCtlLib.IMSVidOutputDevice dev in devices)
{
Console.WriteLine("{0}: {1} - {2}", dev.Name, dev.Status, dev.Power);
}
But the devices.count is always zero. I have two monitors on my dev box.
What am I missing ?
Related
I am enumerating installed applications using WMI, and this block is taking a relatively long time to complete no matter how I structure it. It takes 13 seconds in my environment every time. Is there a better (faster) way to check if a program is installed? (I'm using iTunes as an example program to check for)
private static string Timestamp
{
get { return DateTime.Now.ToString("HH:mm:ss.ffff"); }
}
private static void LoadInstalledPrograms()
{
List<string> installedPrograms = new List<string>();
Console.WriteLine("0 - {0}", Timestamp);
ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
Console.WriteLine("1 - {0}", Timestamp);
ManagementObjectCollection managementObjectCollection = mos.Get();
Console.WriteLine("2 - {0}", Timestamp);
foreach (ManagementObject mo in managementObjectCollection)
{
installedPrograms.Add(mo["Name"].ToString());
}
Console.WriteLine("3 - {0}", Timestamp);
Console.WriteLine("Length - {0}", installedPrograms.Count);
}
SELECT * FROM Win32_Product
0 - 08:08:51.3762
1 - 08:08:51.3942
2 - 08:08:51.4012
3 - 08:09:04.8326
Length - 300
SELECT * FROM Win32_Product WHERE name = 'iTunes'
0 - 08:14:17.6529
1 - 08:14:17.6709
2 - 08:14:17.6779
3 - 08:14:31.0332
Length - 1
SELECT * FROM Win32_Product WHERE name LIKE 'iTunes'
0 - 08:16:38.2719
1 - 08:16:38.2899
2 - 08:16:38.2999
3 - 08:16:51.5113
Length - 1
SELECT name FROM Win32_Product WHERE name LIKE 'iTunes'
0 - 08:19:53.9144
1 - 08:19:53.9324
2 - 08:19:53.9394
3 - 08:20:07.2794
Length - 1
If you query "Win32_product" the msi-installer checks and validates every product.
The KB article http://support.microsoft.com/kb/974524 shows:
Win32_product Class is not query optimized. Queries such as “select * from Win32_Product where (name like 'Sniffer%')” require WMI to use the MSI provider to enumerate all of the installed products and then parse the full list sequentially to handle the “where” clause. This process also initiates a consistency check of packages installed, verifying and repairing the install. With an account with only user privileges, as the user account may not have access to quite a few locations, may cause delay in application launch and an event 11708 stating an installation failure.
Win32reg_AddRemovePrograms is a much lighter and effective way to do this, which avoids the calls to do a resiliency check, especially in a locked down environment. So when using Win32reg_AddRemovePrograms we will not be calling on msiprov.dll and will not be initiating a resiliency check.
So be careful with "Win32_product".
Update: nice article https://sdmsoftware.com/group-policy-blog/wmi/why-win32_product-is-bad-news/
WMI is taking it's time as you already noticed. Iterating through the registry might do the trick for you.
You might have a look at Get installed applications in a system here on stackoverflow, where both methods are mentioned.
As Bernhard points out, WMI use of Win32_Product initiates an integrity check of the package estate, and will hence be quite slow to use - and in special cases it can trigger an MSI self-repair (I have never seen this happen on my machines).
Instead of WMI, you can use the MSI automation interface directly to enumerate the applications installed via Windows Installer packages (MSI files) on the machine. This is very quick and doesn't touch WMI at all.
See this example: how to find out which products are installed - newer product are already installed MSI windows (full blown, but basic and easy to understand VBScript example - do check it out). There are many properties you can retrieve for each product, please consult the MSDN documentation for the MSI automation interface. The linked sample VBScript code and the MSDN documentation taken together should help you get going quickly I hope.
P.S: I know this is an old question, but this issue keeps coming up (specifically the slowness of WMI) - just for future reference.
As mentioned here Registry is not reliable and WMI is slow. Thus for me the best option was using Windows Installer API. Add msi.dll to your references and then adapt the following code to your needs:
public static string GetVersionOfInstalledApplication(string queryName)
{
string name;
string version;
Type type = Type.GetTypeFromProgID("WindowsInstaller.Installer");
Installer installer = Activator.CreateInstance(type) as Installer;
StringList products = installer.Products;
foreach (string productGuid in products)
{
string currName = installer.ProductInfo[productGuid, "ProductName"];
string currVersion = installer.ProductInfo[productGuid, "VersionString"];
if (currName == queryName)
{
name = currName;
version = currVersion;
return version;
}
}
return null;
}
You Should use SELECT Name FROM Win32_Product in WMI Query, it works for me
SELECT * make Load all Data Members, so using it are taking much time
Powershell 5.1 has "get-package" instead.
get-package *chrome*
Name Version Source ProviderName
---- ------- ------ ------------
Google Chrome 109.0.5414.75 msi
Since Vista, Windows is shipped with WIA 2.0 (wiaaut.dll).
According to the following KB article and many of my findings on various forums, duplex scanning is no longer possible using WIA 2.0. Yet, the article mentions the use of native WIA 2.0, what would make duplex scanning possible.
(https://support.microsoft.com/en-us/kb/2709992)
According to the WIA 2.0 documentation (https://msdn.microsoft.com/en-us/library/windows/desktop/ms630196(v=vs.85).aspx), duplex scanning is possible but using the new WIA_IPS_DOCUMENT_HANDLING_SELECT (3088) property.
My issues are:
I have no idea how to use native WIA, I suspect when using C# its just not possible.
I cant find a way to set the new WIA_IPS_DOCUMENT_HANDLING_SELECT property, as the property is not present in my wiaDevice properties. According to WiaDef.h, its property id is still 3088 and the only possible value is 0x400 (1024).
If anyone could help me (and I think many others) out on this, it would be much appreciated!
Greetings,
M.
After a few more hours of searching I found a clue in the following post.
https://stackoverflow.com/a/7580686/3641369
As I used a one-pass duplex scanner, both front and back sides where scanned at the same time. By setting the device properties (device properties, not item properties) Document_Handling_Select to 5 (Feeder + Duplex) and Pages to 1 and calling the transfer method 2 times, I finally got the font and back side of the scan.
Setting wiaDev.Properties["Document Handling Select"] = 5 specifies the use of the feeder and scanning duplex.
Setting wiaDev.Properties["Pages"] = 1 specifies that the scanner should keep 1 page in memory, this allowing to keep both front side and back side of the page in memory during 1 scan pass.
if (duplex)
{
wiaDev.Properties["Document Handling Select"].set_Value(5);
wiaDev.Properties["Pages"].set_Value(1);
}
Getting the Wia item and setting item properties such as color and dpi.
var item = wiaDev.Items[1];
item.Properties["6146"].set_Value((int)clr);
item.Properties["6147"].set_Value(dpi);
item.Properties["6148"].set_Value(dpi);
Then calling the transfer method twice returns two different images
var img = (ImageFile)wiaCommonDialog.ShowTransfer(item, FormatID.wiaFormatJPEG);
ImageFile imgduplex = null;
if(duplex)
imgduplex = (ImageFile)wiaCommonDialog.ShowTransfer(item, FormatID.wiaFormatJPEG);
Hope this helps someone!
I'm making a windows form application using Visual Studio. The application allows you to enter the what you want the photo to be named, and then saves that image to a specific location on the network. It works great when I use it on my laptop. However, when I try to run it on the a desktop, it does not work. Instead I get the message:
System.Runtime.InteropServices.COMException (0x80040217): No
combination of intermediate filters could be found to make the
connection.
at DirectShowLib.DsError.ThrowExceptionForHR(Int32 hr)
at OrderProductCapture.Capture.SetupGraph(DsDevice dev, Int32 iWidth,
Int32 iHeight, Int16 iBPP, Control hControl)
at OrderProductCapture.Capture.ctor(Int32 iDeviceNum, Int32 iWidth,
Int32 iHeight, Int16 iBPP, Control hControl)
at OrderProductCapture.frmMain.ctor()
The Call Stack says:
OrderProductCapture.exe!OrderProductCapture.Capture(int iDeviceNum, int iWidth, int iHeight, short iBPP, System.Windows.Forms.Control hControl) Line 82
OrderProductCapture.exe!OrderProductCapture.frmMain.frmMain() Line 50
OrderProductCapture.exe!OrderProductCapture.Program.Main() Line 19
I have already googled this many times, and I've looked at most of the similar questions on SO. Both computers are using Windows 7 professional. Any help would be fantastic.
This is the code where my code catches the exception. I do not think the code is wrong, because it works fine on my laptop.
public Capture(int iDeviceNum, int iWidth, int iHeight, short iBPP, Control hControl)
{
DsDevice [] capDevices;
// Get the collection of video devices
capDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
if (iDeviceNum + 1 > capDevices.Length)
{
throw new Exception("No video capture devices found at that index!");
}
try
{
// Set up the capture graph
SetupGraph( capDevices[iDeviceNum], iWidth, iHeight, iBPP, hControl);
// tell the callback to ignore new images
m_PictureReady = new ManualResetEvent(false);
}
catch
{
Dispose();
throw;
}
}
When having to convert between media formats, you can programmatically force it to use some specific filter chain and configure it tightly to your needs, but DirectSHOW also has the ability of "guessing" the right tools to use. It knows all the tiny media handlers that are oficially installed in the OS, and tries to match them so that final required "conversion" is built.
However, DirectShow still needs those tiny converters to be installed. DS is able to analyze and connect them, but will not provide you any support for exotic media types. Often, even non-exotic can be problematic if the OS is "fresh-n-clean".
If I remember correctly, that error basically means that (on this problematic machine) some "codecs" are missing.
These things often come with any:
drivers for webcams/microphones/soundcards
audio-processing software (sound editors, media recorders, media players, ..)
"codec packs" like CCCP (really, don't get confused by their logo)
specific codec/filter packages
(...)
First thing I'd now do would be:
recall what I tried to convert
try to read all error messages and logs and find out if there's some faulty filter mentioned, maybe it needs reinstalling
compare what audio-related software is installed on machines where the program WORKS versus the problematic machine
basing on the above, try to deduce what codec is missing
find it, download, install
Also, you may read the code of SetupGraph() function. I bet there's a clear reference to the format that is being used, and this may point out what codec is missing.
Codecs also sometimes get damaged (actually not themselves, but their configuration and registration entries may get damaged). If you are sure that the correct codecs are available on the machine, reinstalling or "repairing" (if they have such option) them can help.
I have coding I almost always use with my Omnikey RFID CardMan 5321 smart cards. Problem is we received new cards today which are marked "HID iCLASS GL" which do not appear to be working well with our coding.
Without going through the whole source, our problem is arising when we are calling the following line, which basically tells us the length of the data:
lResult = SCardTransmit(hCard, 0, bytCommand, lLen, 0, byReadBuffer, iReturnlength)
We are returning only a length of 2, which the data is marked as "x69 x86". Even if I tell it to read all 255 chr's the rest are just marked as null.
Now I know our reader can read these cards since the OMNIKEY Diagnostic tool is showing us the following:
Status: Smart Card Inserted
FW: 5.10
Port: USB
Lib: 1.0
Smart Card Nme: iCLASS 32KS 8x2+16
ART: Valid
Protocol: ISO 15693 (Part 2)
PICCtoPCD: 26,48 kbps
PCDtoPICC: 26,48 kbps
Frequ: 13.56 MHz
As I explained before, everything is working fine in my coding except no data is being returned for my card besides "x69 x86", which is surely not correct.
If anyone has any experience reading from a HID iCLASS card, I would greatly appreciate some feedback on how to. Even if we have to license software, that is ok.
Thanks in advance!
in case you are trying to access physical access data, I would thoroughly check the crypto protocol between reader and host first and also meke sure you are using a reader with teh latest firmware (5.20 for the OMNIKEY 5321).
I would also introduce code to check the card system withour secure communication channel between host and reader application.
Further references:
http://www.hidglobal.com/documents/ok_contactless_developer_guide_an_en.pdf
The reason cause you get a 2 Byte array is cause your command runs on an error so the chip returns only SW1 and SW2 Flag
in your case it's meaning is
x69 --> Command not allowed (further qualification in SW2, see table 17)
x86 --> Command not allowed (no current EF)
So you might proof that your application file on the chip is correctly selected
further information #
http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4_5_basic_organizations.aspx#table17
How to check current machine type? laptop or desktop ?
I got this from http://blog.csdn.net/antimatterworld/archive/2007/11/11/1878710.aspx ,it works well on my home machine(Win2003 on laptop), it returns "Portable", but failed on my work machine(Vista on laptop), it returns "Other".
here is the code:
public enum ChassisTypes
{
Other = 1,
Unknown,
Desktop,
LowProfileDesktop,
PizzaBox,
MiniTower,
Tower,
Portable,
Laptop,
Notebook,
Handheld,
DockingStation,
AllInOne,
SubNotebook,
SpaceSaving,
LunchBox,
MainSystemChassis,
ExpansionChassis,
SubChassis,
BusExpansionChassis,
PeripheralChassis,
StorageChassis,
RackMountChassis,
SealedCasePC
}
public static ChassisTypes GetCurrentChassisType()
{
ManagementClass systemEnclosures = new ManagementClass("Win32_SystemEnclosure");
foreach (ManagementObject obj in systemEnclosures.GetInstances())
{
foreach (int i in (UInt16[ ])(obj["ChassisTypes"]))
{
if (i > 0 && i < 25)
{
return (ChassisTypes)i;
}
}
}
return ChassisTypes.Unknown;
}
Here's a good Microsoft article that suggests looking at a few other WMI classes to get a better idea of whether the computer is a laptop or desktop:
http://technet.microsoft.com/en-us/library/cc180825.aspx
Win32_SystemEnclosure, ChassisTypes(1)=10
Win32_Battery or Win32_PortableBattery
Win32_PCMCIAController
Win32_DriverVXD.Name = "pccard"
Win32_ComputerSystem.Manufacturer
Win32_ComputerSystem.Model
And it also suggests to look in the registry for the Power scheme.
Well, I may be attempting to raise the dead here, but I would suggest that the most reliable method of determining a laptop would be the present of a lid status switch.
See GetPwrCapabilities and System_power_Capabilities
There is no need for both Other and Unknown check.
Change the condition to i > 1 && i < 25 and remember ChassisTypes is an array where OS returns what ever he thinks your system is.
It is possible to match more than single type. Your code only returns the first match.
See http://www.microsoft.com/technet/scriptcenter/resources/qanda/sept04/hey0921.mspx and http://msdn.microsoft.com/en-us/library/aa387204(VS.85).aspx which states that:
This documentation is derived from the CIM class descriptions published by the DMTF.
Presumably, that means the manufacturer had to provide some information for Windows to be able to discover it.
I don't think there is a definitive right answer for this and I've found WMI unreliable for it but I have been using the Win32 function GetSystemPowerStatus() to determine if there is a system battery, obviously system battery == portable computer.
I've never tried this on a desktop with a UPS though?!
I am pretty sure that this will depend on whether the manufacturer has bothered to provide that data on the current chipset. If they have not, then "Other" is the best you can do.
Check out this somewhat related article, which also suggests querying the BIOS directly.
In order to check if machine is laptop or desktop you can try to check battery status, using SystemPowerCapabilites.LidPresent or both of them.
Battery:
if(SystemInformation.PowerStatus.BatteryChargeStatus ==BatteryChargeStatus.NoSystemBattery){
//desktop
}
else{
//laptop
}
SystemPowerCapabilites.LidPresent:
public SYSTEM_POWER_CAPABILITIES getSystemPowerCapabilites(){
{
SYSTEM_POWER_CAPABILITIES systemPowerCapabilites;
GetPwrCapabilities(out systemPowerCapabilites);
return systemPowerCapabilites;
}
getSystemPowerCapabilites().LidPresent;
GetPwrCapabilities definition: http://www.pinvoke.net/default.aspx/powrprof/GetPwrCapabilities.html
read registry key from HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\pcmcia, the ‘Start’ value, it's laptop if start =0, otherwise it's desktop machine if start doesn't exist or start != 0.