Preveting computer from going to sleep with program C# [duplicate] - c#

I have to stop windows from going into sleep when my program is running.
And I don't only want to prevent the sleep-timer, I also want to cancel the sleep-event if I press the sleep-button or in any other way actively tell the computer to sleep. Therefore SetThreadExecutionState is not enough.
Or...I don't actually have to prevent the sleep completely, only delay it 5-10sec to allow my program to finish a task.
(I know that this is bad program behavior but it's only for personal use.)

After considering vim's answer
"Using PowerCreateRequest, PowerSetRequest, and PowerClearRequest
functions is the preferred method."
with the linked AvailabilityRequests.docx on msdn which is exhausting to get into it (too much to read), I have searched the web for a concrete example in c# that is based on the PowerCreateRequest and found http://go4answers.webhost4life.com/Example/problem-monitor-wakeup-service-windows7-12092.aspx [EDIT 2016 - isn't available anymore]
Copied and adapted it to my needs (PInvoke of CloseHandle copied from msdn):
using System.Runtime.InteropServices;
#region prevent screensaver, display dimming and automatically sleeping
POWER_REQUEST_CONTEXT _PowerRequestContext;
IntPtr _PowerRequest; //HANDLE
// Availability Request Functions
[DllImport("kernel32.dll")]
static extern IntPtr PowerCreateRequest(ref POWER_REQUEST_CONTEXT Context);
[DllImport("kernel32.dll")]
static extern bool PowerSetRequest(IntPtr PowerRequestHandle, PowerRequestType RequestType);
[DllImport("kernel32.dll")]
static extern bool PowerClearRequest(IntPtr PowerRequestHandle, PowerRequestType RequestType);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
internal static extern int CloseHandle(IntPtr hObject);
// Availablity Request Enumerations and Constants
enum PowerRequestType
{
PowerRequestDisplayRequired = 0,
PowerRequestSystemRequired,
PowerRequestAwayModeRequired,
PowerRequestMaximum
}
const int POWER_REQUEST_CONTEXT_VERSION = 0;
const int POWER_REQUEST_CONTEXT_SIMPLE_STRING = 0x1;
const int POWER_REQUEST_CONTEXT_DETAILED_STRING = 0x2;
// Availablity Request Structures
// Note: Windows defines the POWER_REQUEST_CONTEXT structure with an
// internal union of SimpleReasonString and Detailed information.
// To avoid runtime interop issues, this version of
// POWER_REQUEST_CONTEXT only supports SimpleReasonString.
// To use the detailed information,
// define the PowerCreateRequest function with the first
// parameter of type POWER_REQUEST_CONTEXT_DETAILED.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct POWER_REQUEST_CONTEXT
{
public UInt32 Version;
public UInt32 Flags;
[MarshalAs(UnmanagedType.LPWStr)]
public string
SimpleReasonString;
}
[StructLayout(LayoutKind.Sequential)]
public struct PowerRequestContextDetailedInformation
{
public IntPtr LocalizedReasonModule;
public UInt32 LocalizedReasonId;
public UInt32 ReasonStringCount;
[MarshalAs(UnmanagedType.LPWStr)]
public string[] ReasonStrings;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct POWER_REQUEST_CONTEXT_DETAILED
{
public UInt32 Version;
public UInt32 Flags;
public PowerRequestContextDetailedInformation DetailedInformation;
}
#endregion
/// <summary>
/// Prevent screensaver, display dimming and power saving. This function wraps PInvokes on Win32 API.
/// </summary>
/// <param name="enableConstantDisplayAndPower">True to get a constant display and power - False to clear the settings</param>
private void EnableConstantDisplayAndPower(bool enableConstantDisplayAndPower)
{
if (enableConstantDisplayAndPower)
{
// Set up the diagnostic string
_PowerRequestContext.Version = POWER_REQUEST_CONTEXT_VERSION;
_PowerRequestContext.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
_PowerRequestContext.SimpleReasonString = "Continuous measurement"; // your reason for changing the power settings;
// Create the request, get a handle
_PowerRequest = PowerCreateRequest(ref _PowerRequestContext);
// Set the request
PowerSetRequest(_PowerRequest, PowerRequestType.PowerRequestSystemRequired);
PowerSetRequest(_PowerRequest, PowerRequestType.PowerRequestDisplayRequired);
}
else
{
// Clear the request
PowerClearRequest(_PowerRequest, PowerRequestType.PowerRequestSystemRequired);
PowerClearRequest(_PowerRequest, PowerRequestType.PowerRequestDisplayRequired);
CloseHandle(_PowerRequest);
}
}

I had a problem like this with a hardware device connected via usb. XP /Vista would sleep/hibernate right in the middle of ... Great you say, when it resumes it can just continue. If the hardware is still connected!!!
Users have the habit of pulling cables out whenever they feel like it.
You need to handle XP and Vista
Under XP trap the WM_POWERBROADCAST and look for the PBT_APMQUERYSUSPEND wparam.
// See if bit 1 is set, this means that you can send a deny while we are busy
if (message.LParam & 0x1)
{
// send the deny message
return BROADCAST_QUERY_DENY;
} // if
else
{
return TRUE;
} // else
Under Vista use SetThreadExecutionState like this
// try this for vista, it will fail on XP
if (SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED) == NULL)
{
// try XP variant as well just to make sure
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
} // if
and when you app has finished set it back to normal
// set state back to normal
SetThreadExecutionState(ES_CONTINUOUS);

Using PowerCreateRequest, PowerSetRequest, and PowerClearRequest functions is the preferred method. Details and sample code (C/C#) are inside http://msdn.microsoft.com/en-us/library/windows/hardware/gg463205.aspx

set wsc = CreateObject("WScript.Shell")
Do
WScript.Sleep (60*1000)
wsc.SendKeys ("{SCROLLLOCK 2}")
Loop
-put the above code in notepad and save the file as .vbs and double click the file

The same technique applies as for preventing the screensaver should be used. See Programmatically prevent Windows screensaver from starting.
Note that some security settings can override this (forcing computers to lock after a certain time is one).

If you need a display that should work until your application is running then try to set "ES_DISPLAY_REQUIRED" instead of away mode:
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
Once you are done with your application make sure to clear all other flags.
SetThreadExecutionState(ES_CONTINUOUS);

How about waking it back up if it goes to sleep?
http://www.enterprisenetworksandservers.com/monthly/art.php?1049

Below is my attempt using the modern power availability request API (supersedes SetThreadExecutionState), as suggested by vim.
I'm using a nice P/Invoke NuGet I came across, Vanara.PInvoke.Kernel32:
using Vanara.PInvoke;
using static Vanara.PInvoke.Kernel32;
// create request object
using var request = PowerCreateRequest(new REASON_CONTEXT("App FOO is working"));
if (request.IsInvalid)
{
throw new InvalidOperationException(
$"Could not create power availability request: {Win32Error.GetLastError()}");
}
// send request
if (!PowerSetRequest(request, POWER_REQUEST_TYPE.PowerRequestSystemRequired))
{
throw new InvalidOperationException(
$"Could not send power availability request: {Win32Error.GetLastError()}");
}
// do stuff that required the machine to be up
Console.WriteLine("Doing stuff...");
await Task.Delay(5000);
// clear request
if (!PowerClearRequest(request, POWER_REQUEST_TYPE.PowerRequestSystemRequired))
{
Console.WriteLine(
"WARNING: Could not clear power availability request: {0}",
Win32Error.GetLastError());
}
You can see your request in action by issuing powercfg /requests from an admin terminal.

Related

I/O exception error when using serialport.open()

FINAL UPDATE
It was our firmware the whole time. Embarrassing to a degree, but I'm happy we can move forward and I can put learning Java off for another day. My answer is below.
UPDATE
So I have more or less given up on this. I think it is a bug that goes down to the API, but I have neither the time, resources nor skill-set to get to the bottom of it. I think there exists some hardware to whom Windows just gives the middle finger. I have downloaded Eclipse, switched to Java and will try to see if that works. If not, you'll see me back here. However, I would absolutely love to solve this and so if anyone has the time or inclination to dig deep into this one, I'd love to see what you come up with. Obviously I will be checking back here from time to time. Please make sure you '#' me in your comments so I am alerted.
ORIGINAL POST
I know there are a few other people dealing with this issue, but I was hoping someone could help me. I am trying to connect to a COM port, but I am getting an I/O exception when I try to use the serialport.Open() command:
System.IO.IOException: The parameter is incorrect.
at System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)
at System.IO.Ports.InternalResources.WinIOError()
at System.IO.Ports.SerialStream.InitializeDCB(Int32 baudRate, Parity parity, Int32 dataBits, StopBits stopBits, Boolean discardNull)
at System.IO.Ports.SerialStream..ctor(String portName, Int32 baudRate, Parity parity, Int32 dataBits, StopBits stopBits, Int32 readTimeout, Int32 writeTimeout, Handshake handshake, Boolean dtrEnable, Boolean rtsEnable, Boolean discardNull, Byte parityReplace)
at System.IO.Ports.SerialPort.Open()
at *programtitlehere.cs*:line 90
I am using a Stellaris LM4F232 to emulate a COM port. I can open, access and I get good results using Termite (a terminal program), but whenever I try with Visual Studio it won't even connect, and I get this error. Now I don't even really know what this error means and despite trying to read elsewhere, I still feel lost.
Can anyone explain to me what is happening here and maybe I can begin to try to figure this out? I can include more code, but to be honest there isn't much there; all the properties of the serial port device are as normal, and it is only happening with this device (I can use an MSP430 no problem with the same details).
My code is shown below for people who would like to see it (note this is just a 'sandbox', not the actual program, but the symptoms are identical):
try
{
serialPort1.PortName = "COM5";
serialPort1.Open();
if (serialPort1.IsOpen == true)
{
textBox1.Text = "CONNECTED";
}
else
{
textBox1.Text = "NOT CONNECTED";
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.ToString(), "ERROR");
}
and the other settings are done with the property manager (the only difference is baud is set to 230400; all others are on their default).
I can open up COM4 with this (an MSP430) which for all intents and purposes is an identical device. I can open COM5 with Termite, so I know the connection is good). And no, I am not trying to open them at the same time. If you need more information let me know and I can post more.
EDIT: I'm on day three of trying to figure this out and still no luck. I don't really understand why I can access this COM port through a terminal program and not my own when, as near as I can see, there is absolutely no difference. Is there a program that can 'examine' a COM port to see the properties of it (besides Windows manager I mean)? I'm getting pretty frustrated and am sort of at a stand still in my project until I figure this out...
EDIT2: I've found an apparent workaround, but I've yet to get it to work here. Now I get a few different I/O errors, but at least it is motion (not sure if it is progress). I've also learned that this is a .NET bug, which has existed since 2.0. I'd still love any help, but if I figure it out I will report back. Zach's code (the workaround linked above) is shown below:
using System;
using System.IO;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;
namespace SerialPortTester
{
public class SerialPortFixer : IDisposable
{
public static void Execute(string portName)
{
using (new SerialPortFixer(portName))
{
}
}
#region IDisposable Members
public void Dispose()
{
if (m_Handle != null)
{
m_Handle.Close();
m_Handle = null;
}
}
#endregion
#region Implementation
private const int DcbFlagAbortOnError = 14;
private const int CommStateRetries = 10;
private SafeFileHandle m_Handle;
private SerialPortFixer(string portName)
{
const int dwFlagsAndAttributes = 0x40000000;
const int dwAccess = unchecked((int) 0xC0000000);
if ((portName == null) || !portName.StartsWith("COM", StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException("Invalid Serial Port", "portName");
}
SafeFileHandle hFile = CreateFile(#"\\.\" + portName, dwAccess, 0, IntPtr.Zero, 3, dwFlagsAndAttributes,
IntPtr.Zero);
if (hFile.IsInvalid)
{
WinIoError();
}
try
{
int fileType = GetFileType(hFile);
if ((fileType != 2) && (fileType != 0))
{
throw new ArgumentException("Invalid Serial Port", "portName");
}
m_Handle = hFile;
InitializeDcb();
}
catch
{
hFile.Close();
m_Handle = null;
throw;
}
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int FormatMessage(int dwFlags, HandleRef lpSource, int dwMessageId, int dwLanguageId,
StringBuilder lpBuffer, int nSize, IntPtr arguments);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool GetCommState(SafeFileHandle hFile, ref Dcb lpDcb);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetCommState(SafeFileHandle hFile, ref Dcb lpDcb);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool ClearCommError(SafeFileHandle hFile, ref int lpErrors, ref Comstat lpStat);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode,
IntPtr securityAttrs, int dwCreationDisposition,
int dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern int GetFileType(SafeFileHandle hFile);
private void InitializeDcb()
{
Dcb dcb = new Dcb();
GetCommStateNative(ref dcb);
dcb.Flags &= ~(1u << DcbFlagAbortOnError);
SetCommStateNative(ref dcb);
}
private static string GetMessage(int errorCode)
{
StringBuilder lpBuffer = new StringBuilder(0x200);
if (
FormatMessage(0x3200, new HandleRef(null, IntPtr.Zero), errorCode, 0, lpBuffer, lpBuffer.Capacity,
IntPtr.Zero) != 0)
{
return lpBuffer.ToString();
}
return "Unknown Error";
}
private static int MakeHrFromErrorCode(int errorCode)
{
return (int) (0x80070000 | (uint) errorCode);
}
private static void WinIoError()
{
int errorCode = Marshal.GetLastWin32Error();
throw new IOException(GetMessage(errorCode), MakeHrFromErrorCode(errorCode));
}
private void GetCommStateNative(ref Dcb lpDcb)
{
int commErrors = 0;
Comstat comStat = new Comstat();
for (int i = 0; i < CommStateRetries; i++)
{
if (!ClearCommError(m_Handle, ref commErrors, ref comStat))
{
WinIoError();
}
if (GetCommState(m_Handle, ref lpDcb))
{
break;
}
if (i == CommStateRetries - 1)
{
WinIoError();
}
}
}
private void SetCommStateNative(ref Dcb lpDcb)
{
int commErrors = 0;
Comstat comStat = new Comstat();
for (int i = 0; i < CommStateRetries; i++)
{
if (!ClearCommError(m_Handle, ref commErrors, ref comStat))
{
WinIoError();
}
if (SetCommState(m_Handle, ref lpDcb))
{
break;
}
if (i == CommStateRetries - 1)
{
WinIoError();
}
}
}
#region Nested type: COMSTAT
[StructLayout(LayoutKind.Sequential)]
private struct Comstat
{
public readonly uint Flags;
public readonly uint cbInQue;
public readonly uint cbOutQue;
}
#endregion
#region Nested type: DCB
[StructLayout(LayoutKind.Sequential)]
private struct Dcb
{
public readonly uint DCBlength;
public readonly uint BaudRate;
public uint Flags;
public readonly ushort wReserved;
public readonly ushort XonLim;
public readonly ushort XoffLim;
public readonly byte ByteSize;
public readonly byte Parity;
public readonly byte StopBits;
public readonly byte XonChar;
public readonly byte XoffChar;
public readonly byte ErrorChar;
public readonly byte EofChar;
public readonly byte EvtChar;
public readonly ushort wReserved1;
}
#endregion
#endregion
}
internal class Program
{
private static void Main(string[] args)
{
SerialPortFixer.Execute("COM1");
using (SerialPort port = new SerialPort("COM1"))
{
port.Write("test");
}
}
}
}
EDIT3: Day 6: I'm still plugging away at this. My water rations are low, but still I struggle on. I feel help must surely be on the horizon. Whoever finds this journal bring my remains back to Canada and find Nicole. Tell her I love her.
But seriously, I have no idea what is causing this problem. I'm wondering if it is purely on the embedded side; maybe because it is USB On-The-Go (OTG), or because the device is capable of being a host also. Has anyone run into that problem? It doesn't explain why I can use Termite (a terminal program, for those viewers just joining us) though. I have been trying to find an open source terminal program that a) works and b) see a). As per usual, I will report back if I discover the issue here as I have now found countless forums where it sounds people have had this issue dating back to 2006.
EDIT4: So as per the advice given, I downloaded a port monitoring software application (I got Eltima Serial Port Monitor), and it does look like a baud issue:
But strangely no matter what baud I set, it still fails. And also can someone explain what the up/down thing means? I tried googling it, but the keywords are too general. As usual, I will keep reporting back any changes.
Also, for the record, I can connect using Eltima at a baud of 115200 (same as Termite). Unfortunately this does not work in Visual Studio.
EDIT5: Our plot takes a surprise twist. I was monitoring what happens when Termite connects to the COM port in question and BLAM! Termite throws the exact same error as my program, but it ignores it. Genius, right? Sloppy, but it works. Now I need to learn how to ignore IOExceptions. I'll report back when I get it figured out.
EDIT6: So as it turns out it is a baud rate issue, but it goes deeper. I have been using Eltima Serial Port Monitoring software, and it is very intuitive and easy to use. I would recommend it. After some research I have learned that you cannot ignore this exception and still connect to the serial port using .NET's library.
So I have to go deeper into the Win32 API and write my own. I have found a few pages that touch on this, but to be honest I have never done anything like this before, so it may be a while before I report back, but I will definitely figure this out and get back to everyone. There are way too many who suffer from this problem.
I have found quite a few forums and websites where I can see the exact same symptoms, but nobody has really done much besides say 'Yeah, .NET sucks'. I plan on writing a full static library class and then publish either on my website, here and wherever else I can. Hopefully .NET will take notice (this bug has existed since 2.0).
This comes from the serial port driver; it is unhappy about one of the settings. With baudrate being a good candidate, drivers tend to allow only up to 115200. Albeit that this should not be a restriction when this is a dedicated CAN bus product.
The best way to tackle this is by using Sysinternals' Portmon utility; you can see what is being sent to the driver. Observe it for Terminate first; that's your known-to-work baseline. Then tinker with SerialPort properties until the initialization commands, as you see them in PortMon, sent by your program matches Termite's. Just the values, not the order. If that doesn't pan out either then take it to the parking lot and back over it with your car several times and buy another brand.
Update: it certainly looks like a baudrate problem. That's an issue in .NET; it is not going to ignore the driver's error return code like your terminal emulator programs do. The actual value should not matter since you are talking to an emulated serial port. There is however a possible issue with the CAN bus speed; rates are variable and it isn't clear to me how they are negotiated. This tended to be done with DIP switches in the olden days, and it may well be that the driver wants you to specify the speed through the baudrate setting. There ought to be something about it on the box or in the manual. Typical speeds are 40, 250 or 500 kbit/s. The manufacturer certainly would know; give them a call.
I faced a similar problem as reported in this thread, but I managed to solve the problem!
I am using STM32F2xx for the VCP!
And indeed it was my firmware problem. I forgot to include serial port settings in my USB callback!
The process of connecting a serial port from PC and firmware:
When a PC opens a serial port communication, the PC will send some command into the "configuration endpoint"
In the firmware, it would have a callback and the firmware will provide all the USB information (they call it a USB descriptor)
USB information is the configuration of each endpoint, (for example, latency, data size transmission, and type of USB - high speed or low speed)
Once the firmware has completed sending all the information, the PC will acknowledge and USB communication is successfully opened
Then, the PC will send a command to get the serial port settings from the firmware
Serial port settings are baudrate, data parity, and bit length.
In firmware, it should reply the serial port settings back to PC (my mistake occurs here; I didn’t not send any serial port settings back to the PC)
If successful, PC will start the serial port communication!
If failed, PC will give an open serial port error (but, do note that this error sometimes is bypassed)
In STM32 firmware code:
static int8_t CDC_Control_FS (uint8_t cmd, uint8_t* pbuf, uint16_t length)
{
switch (cmd) {
case CDC_GET_LINE_CODING:
{
// I was missing this part
uint32_t baudrate = 9600;
pbuf[0] = (uint8_t)(baudrate);
pbuf[1] = (uint8_t)(baudrate >> 8);
pbuf[2] = (uint8_t)(baudrate >> 16);
pbuf[3] = (uint8_t)(baudrate >> 24);
pbuf[4] = 0;
pbuf[5] = 0;
pbuf[6] = 8;
break;
}:
....
I ran into the same situation. I am trying to connect serial communication to my 3G USB Dongle (Huawei E303F) at /dev/ttyUSB0. I use Mono in Raspbian (Raspberry Pi 2). On my development PC and macOS, my program runs fine. But when I deploy it into Raspbian, I got the IOException Broken Pipe error on Serial.Open().
It took me three days of debugging, and I tried all possible solutions. Finally I found that I have to set...
serialPort.DtrEnable = true;
serialPort.RtsEnable = true;
Before calling .Open().
And so our thrilling tale comes to a close. It was firmware the whole time (i.e. the code on the embedded device). We changed up a few functions and essentially poked around, chopped, added and altogether cleaned up the code and voila, the code is working. This pic sums it up pretty well. Curse you firmware!!
However, the bug described in my (lengthy) question still persists for many people and I know there are lots of people out there who still have it. All I can say is good luck and quadruple check your firmware (apparently triple checking it isn't enough these days).
I had the same problem and setting the baud rate to 1 fixed it!

Disable Suspend in Window CE

I have a system that requires the application to always be running.
I have set all of the registry settings in [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\Timeouts] to 0 (which I am told should disable the timeout).
The system is still suspending, we are running on Windows CE 6.0 R3 in Full Power Management mode.
Like in AAT's answer, you have to trigger reload event. Working implementation below:
private static void DoAutoResetEvent()
{
string eventString = "PowerManager/ReloadActivityTimeouts";
IntPtr newHandle = CreateEvent(IntPtr.Zero, false, false, eventString);
EventModify(newHandle, (int)EventFlags.EVENT_SET);
CloseHandle(newHandle);
}
private enum EventFlags
{
EVENT_PULSE = 1,
EVENT_RESET = 2,
EVENT_SET = 3
}
[DllImport("coredll.dll", SetLastError = true)]
private static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
[DllImport("coredll")]
static extern bool EventModify(IntPtr hEvent, int func);
[DllImport("coredll.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hObject);
After you make any changes to the Control\Power\Timeouts registry entries you need to kick a special event so that the system knows to reload the timeout settings. It is a named event called PowerManager/ReloadActivityTimeouts so you need a snippet like
HANDLE hEvent = CreateEvent(NULL,
FALSE,
FALSE,
_T("PowerManager/ReloadActivityTimeouts"));
if(hEvent != NULL)
{
SetEvent(hEvent);
CloseHandle(hEvent);
}
(That is verbatim from our Win CE application which sets up and turns off timeouts according to the users' wishes.)
Another method which works equally well, but may be considered a hack is to periodically output a fake keypress. This function can be used:
keybd_event(VKEY_F24, 0, KEYEVENTF_KEYUP, 0);
If you output a non-existant key such as VKEY_F24 and use the keyup code, that will keep the system awake and be ignored by the running applications. Depending on your system's default timeout, this may need to be done once every 30 seconds.

C# - Read Parallel Port State (Simple Push Switch)

I am updating in C# some software that was originally written in VC++ V1.0 for DOS6.
One aspect of the software is a check on the parallel port, where a simple push-button switch is connected. I don't currently know to which two pins the switch is connected, but I have the source for the old program, the relevant sections of which are below...
#define switch_mask 0x10
void main(int argc, char *argv[])
{
int NewState = 0, OldState = 0;
/* Check switch */
NewState = _bios_printer (_PRINTER_STATUS, 0, 0);
if (NewState != OldState)
{
checkParallelPort (NewState);
OldState = NewState;
}
}
void checkParallelPort (int portState)
{
int SwitchState;
/* Switch bit is Active LOW */
SwitchState = (portState & switch_mask) ? 1 : 0;
}
Now _bios_printer (within bios.h) is obviously not available to me in C#, but I'm struggling to find an alternative that can do this simple task.
Info on _bios_printer is here. I've done plenty of searching for reading/writing to/from the parallel port in .Net, but nothing seems to provide me with the port status.
Also, can you conclude from this code (and how it checks the 'status') where the two switch wires are connected on the DB25 plug?
I'd be grateful if anyone has some help/advice on this please.
Many thanks
It seems to be checking 'Error', pin 15. IIRC, this is pulled up internally, so your switch should pull down pin 15. Connect it between pins 15 and 18.
There are some drivers available that allow the reading of the I/O map ports. You will have to import and make DLL calls and then almost certainly poll the pin :((
I do wish this interface was dead and buried!
Thanks for the reply. Here's what I ended up with...
I used this tutorial on CodeProject...
http://www.codeproject.com/KB/vb/Inpout32_read.aspx
When converted to C#, I used something similar to below. (Apologies if there is an error - I 'paraphrased' the code below from what i've ended up with - it works for me!)
private void button1_Click(object sender, EventArgs e)
{
short InReg = 0x379; // Location of Port Status register
int NewState; // int named NewState
NewState = InpOut32_Declarations.Inp(InReg); //Now NewState has the values in 'Status port'
MessageBox.Show(NewState); //A popup will indicate the current value of NewState
}
static class InpOut32_Declarations
{
[DllImport("inpout32.dll", EntryPoint = "Inp32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
//Inp and Out declarations for port I/O using inpout32.dll.
public static extern int Inp(ushort PortAddress);
[DllImport("inpout32.dll", EntryPoint = "Out32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern void Out(ushort PortAddress, short Value);
}
Interestingly, as my Parallel Port starts at 0xE800 and not 0x378, I had to modify the source of inpout32.dll as the out32 method only accepts a short and 0xE800 is too big for a short! changed it to unsigned short.
Thanks for your help

Find out programmatically if a process is demanding user input

How can I programmatically (in C#) determine, if ANOTHER foreign application (native, java, .NET or whatever...) is currently demanding user input? Can this be done fully in Managed code?
What I'm looking for is the implementation of:
static Boolean IsWaitingForUserInput(String processName)
{
???
}
By demanding user input I mean when an application asks the user to enter some data or quit an error message (Modal dialogs) and is not able to perform its normal tasks anymore. A drawing application that is waiting for the user to draw something is not meant here.
PS: After edits to reflect the comments at the bottom and make the concern clearer, some comments and answers may not be 100% consistent with the question. Take this into account when evaluating the answers and remarks.
It's in general impossible. Take for instance a common kind of application, a word processor. Nowadays that will be running spellchecks in the background, it periodically auto-saves your document, etcetera. Yet from a users perspective it's waiting for input all the time.
Another common case would be a slideshow viewer. At any moment in time you could press a key to advance a slide. Yet your typical user would not view this as "waiting for input".
To summarize: "waiting for input" is a subjective state and therefore cannot be determined programmatically.
How do you like this?
I worked out a solution that seems to work, please notify me in case of problems with this code so I also gain benefit of improvements. It works for Excel as far as I tested. The only issue I dislike is that I had to use unmanaged calls. It also handles the case when an application is based on a dialog like for MFC, derived from CDialog.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;
namespace Util
{
public class ModalChecker
{
public static Boolean IsWaitingForUserInput(String processName)
{
Process[] processes = Process.GetProcessesByName(processName);
if (processes.Length == 0)
throw new Exception("No process found matching the search criteria");
if (processes.Length > 1)
throw new Exception("More than one process found matching the search criteria");
// for thread safety
ModalChecker checker = new ModalChecker(processes[0]);
return checker.WaitingForUserInput;
}
#region Native Windows Stuff
private const int WS_EX_DLGMODALFRAME = 0x00000001;
private const int GWL_EXSTYLE = (-20);
private delegate int EnumWindowsProc(IntPtr hWnd, int lParam);
[DllImport("user32")]
private extern static int EnumWindows(EnumWindowsProc lpEnumFunc, int lParam);
[DllImport("user32", CharSet = CharSet.Auto)]
private extern static uint GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32")]
private extern static uint GetWindowThreadProcessId(IntPtr hWnd, out IntPtr lpdwProcessId);
#endregion
// The process we want the info from
private Process _process;
private Boolean _waiting;
private ModalChecker(Process process)
{
_process = process;
_waiting = false; //default
}
private Boolean WaitingForUserInput
{
get
{
EnumWindows(new EnumWindowsProc(this.WindowEnum), 0);
return _waiting;
}
}
private int WindowEnum(IntPtr hWnd, int lParam)
{
if (hWnd == _process.MainWindowHandle)
return 1;
IntPtr processId;
GetWindowThreadProcessId(hWnd, out processId);
if (processId.ToInt32() != _process.Id)
return 1;
uint style = GetWindowLong(hWnd, GWL_EXSTYLE);
if ((style & WS_EX_DLGMODALFRAME) != 0)
{
_waiting = true;
return 0; // stop searching further
}
return 1;
}
}
}
If I understand you well, you may try to enumerate the process's threads and check their states. Windows Task Manager does something similar. This however will require Win32 functions - Thread32First and Thread32Next among others - but you can achieve this by the simplest use of P/Invoke in C#:
[DllImport("Executor.dll")]
public static extern bool Thread32First(IntPtr handle, IntPtr threadEntry32);
(Precise signature may differ).
EDIT: Ok, there are corresponding functions in the .NET library.
If possible, rewrite the other code to be a concurrent input processor (similar to the algorithm for a concurrent web server):
Wait for input
Fork process
Parent: Repeat
Child: (Worker) handle input
Of course, you could still have your function:
static Boolean IsWaitingForUserInput(String processName) {
return true;
}

EntryPointNotFoundException when using TaskDialog in C#

I'm using the following code to call a TaskDialog.
[DllImport("ComCtl32", CharSet = CharSet.Unicode, PreserveSig = false)]
internal static extern void TaskDialogIndirect(
[In] ref TASKDIALOGCONFIG pTaskConfig,
[Out] out int pnButton,
[Out] out int pnRadioButton,
[Out] out bool pfVerificationFlagChecked);
However, I get the exception "Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32'."
I took this code. I am using Windows 7 x64 (RC).
What am I doing wrong?
Nothing except this is a vista feature
UPDATE:
This probem had to do with side by side assemblies: these functions are present only in comctl32.dll version 6, but, for compatibility reasons, Vista will load an earlier version unless you tell it otherwise. The approach most people (including me) have been taking is to use a manifest. This has proven to be tricky, and may not be the right solution anyway, especially if what you're writing is a library: you don't necessarily want to force the entire application to use common controls 6.
The right solution is to push a new activation context when calling one of the Vista-only APIs. The activation context will use the correct version of comctl32.dll while leaving the rest of the application alone, and no manifest is required.
Fortunately, this is easy to do.Some complete code that already exists MS Knowledgebase. The code from the article (KB 830033) does the trick as is.
Alternative Managed API:
A full wrapper for Vista's TaskDialog & TaskDialogIndirect can be found here:
http://code.msdn.microsoft.com/WindowsAPICodePack
For WPF use the following:
Download the 'VistaBridge Sample Library' from http://code.msdn.microsoft.com/VistaBridge once downloaded, open the project and then build it (if you want to look through all the code, examine the files in the \Library or \Interop folders). You can now take the DLL from VistaBridge\bin\debug\ and add a reference to it in your project, as well you must add a using statement for each of the different VistaBridge modules. For Example:
using Microsoft.SDK.Samples.VistaBridge.Interop or .Library or .Properties or .Services - Depending on your needs.
The VistaBridge project includes API's for many other Vista Features (such as the TaskDialog, Vista OpenFile and SaveFile Dialogs, and of course the Aero Glass Effects) to try these out, run the VistaBridge Project.
The use of Task Dialog requires version 6 of the Windows Common Controls DLL(ComCtl32.dll)! For compatibility reasons, applications don’t bind to this version by default. One way to bind to version 6 is to place a manifest file alongside your executable (named YourAppName.exe.manifest), with the following content:
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
This manifest can also be embedded as a Win32 resource inside your executable (with the name RT_MANIFEST and ID set to 1), if you don’t want to have the extra standalone file. Visual Studio can do this work for you, if you associate your manifest file in your project’s properties.
Based on almog.ori's answer (which got some orphaned links) I made a small change to the linked code, I puzzled around several days:
MS Knowledgebase helped (Archiv), Full Code with adoptions made by me:
using System.Runtime.InteropServices;
using System;
using System.Security;
using System.Security.Permissions;
using System.Collections;
using System.IO;
using System.Text;
namespace MyOfficeNetAddin
{
/// <devdoc>
/// This class is intended to use with the C# 'using' statement in
/// to activate an activation context for turning on visual theming at
/// the beginning of a scope, and have it automatically deactivated
/// when the scope is exited.
/// </devdoc>
[SuppressUnmanagedCodeSecurity]
internal class EnableThemingInScope : IDisposable
{
// Private data
private IntPtr cookie; // changed cookie from uint to IntPtr
private static ACTCTX enableThemingActivationContext;
private static IntPtr hActCtx;
private static bool contextCreationSucceeded = false;
public EnableThemingInScope(bool enable)
{
if (enable)
{
if (EnsureActivateContextCreated())
{
if (!ActivateActCtx(hActCtx, out cookie))
{
// Be sure cookie always zero if activation failed
cookie = IntPtr.Zero;
}
}
}
}
// Finalizer removed, that could cause Exceptions
// ~EnableThemingInScope()
// {
// Dispose(false);
// }
void IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (cookie != IntPtr.Zero)
{
if (DeactivateActCtx(0, cookie))
{
// deactivation succeeded...
cookie = IntPtr.Zero;
}
}
}
private bool EnsureActivateContextCreated()
{
lock (typeof(EnableThemingInScope))
{
if (!contextCreationSucceeded)
{
// Pull manifest from the .NET Framework install
// directory
string assemblyLoc = null;
FileIOPermission fiop = new FileIOPermission(PermissionState.None);
fiop.AllFiles = FileIOPermissionAccess.PathDiscovery;
fiop.Assert();
try
{
assemblyLoc = typeof(Object).Assembly.Location;
}
finally
{
CodeAccessPermission.RevertAssert();
}
string manifestLoc = null;
string installDir = null;
if (assemblyLoc != null)
{
installDir = Path.GetDirectoryName(assemblyLoc);
const string manifestName = "XPThemes.manifest";
manifestLoc = Path.Combine(installDir, manifestName);
}
if (manifestLoc != null && installDir != null)
{
enableThemingActivationContext = new ACTCTX();
enableThemingActivationContext.cbSize = Marshal.SizeOf(typeof(ACTCTX));
enableThemingActivationContext.lpSource = manifestLoc;
// Set the lpAssemblyDirectory to the install
// directory to prevent Win32 Side by Side from
// looking for comctl32 in the application
// directory, which could cause a bogus dll to be
// placed there and open a security hole.
enableThemingActivationContext.lpAssemblyDirectory = installDir;
enableThemingActivationContext.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
// Note this will fail gracefully if file specified
// by manifestLoc doesn't exist.
hActCtx = CreateActCtx(ref enableThemingActivationContext);
contextCreationSucceeded = (hActCtx != new IntPtr(-1));
}
}
// If we return false, we'll try again on the next call into
// EnsureActivateContextCreated(), which is fine.
return contextCreationSucceeded;
}
}
// All the pinvoke goo...
[DllImport("Kernel32.dll")]
private extern static IntPtr CreateActCtx(ref ACTCTX actctx);
// changed from uint to IntPtr according to
// https://www.pinvoke.net/default.aspx/kernel32.ActiveActCtx
[DllImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ActivateActCtx(IntPtr hActCtx, out IntPtr lpCookie);
// changed from uint to IntPtr according to
// https://www.pinvoke.net/default.aspx/kernel32.DeactivateActCtx
[DllImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeactivateActCtx(int dwFlags, IntPtr lpCookie);
private const int ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID = 0x004;
private struct ACTCTX
{
public int cbSize;
public uint dwFlags;
public string lpSource;
public ushort wProcessorArchitecture;
public ushort wLangId;
public string lpAssemblyDirectory;
public string lpResourceName;
public string lpApplicationName;
}
}
}
I then used it that way:
using (new EnableThemingInScope(true))
{
// The call all this mucking about is here for.
VistaUnsafeNativeMethods.TaskDialogIndirect(ref config, out result, out radioButtonResult, out verificationFlagChecked);
}
in TaskDialogInterop.cs provided in WPF Task Dialog Wrapper on GitHub
For more info on possible SEHExceptions in the Finalizer of EnableThemingInScope see this Question on SO

Categories