I write an app in C#, .NET 3.0 in VS2005 with a feature of monitoring insertion/ejection of various removable drives (USB flash disks, CD-ROMs etc.). I did not want to use WMI, since it can be sometimes ambiguous (e.g. it can spawn multiple insertion events for a single USB drive), so I simply override the WndProc of my mainform to catch the WM_DEVICECHANGE message, as proposed here. Yesterday I run into a problem when it turned out that I will have to use WMI anyway to retrieve some obscure disk details like a serial number. It turns out that calling WMI routines from inside the WndProc throws the DisconnectedContext MDA.
After some digging I ended with an awkward workaround for that. The code is as follows:
// the function for calling WMI
private void GetDrives()
{
ManagementClass diskDriveClass = new ManagementClass("Win32_DiskDrive");
// THIS is the line I get DisconnectedContext MDA on when it happens:
ManagementObjectCollection diskDriveList = diskDriveClass.GetInstances();
foreach (ManagementObject dsk in diskDriveList)
{
// ...
}
}
private void button1_Click(object sender, EventArgs e)
{
// here it works perfectly fine
GetDrives();
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_DEVICECHANGE)
{
// here it throws DisconnectedContext MDA
// (or RPC_E_WRONG_THREAD if MDA disabled)
// GetDrives();
// so the workaround:
DelegateGetDrives gdi = new DelegateGetDrives(GetDrives);
IAsyncResult result = gdi.BeginInvoke(null, "");
gdi.EndInvoke(result);
}
}
// for the workaround only
public delegate void DelegateGetDrives();
which basically means running the WMI-related procedure on a separate thread - but then, waiting for it to complete.
Now, the question is: why does it work, and why does it have to be that way? (or, does it?)
I don't understand the fact of getting the DisconnectedContext MDA or RPC_E_WRONG_THREAD in the first place. How does running GetDrives() procedure from a button click event handler differs from calling it from a WndProc? Don't they happen on the same main thread of my app? BTW, my app is completely single-threaded, so why all of the sudden an error referring to some 'wrong thread'? Does the use of WMI imply multithreading and special treatment of functions from System.Management?
In the meantime I found another question related to that MDA, it's here. OK, I can take it that calling WMI means creating a separate thread for the underlying COM component - but it still does not occur to me why no-magic is needed when calling it after a button is pressed and do-magic is needed when calling it from the WndProc.
I'm really confused about that and would appreciate some clarification on that matter. There are only a few worse things than having a solution and not knowing why it works :/
Cheers,
Aleksander
There is a rather long discussion of COM Apartments and message pumping here. But the main point of interest is the message pump is used to ensure that calls in a STA are properly marshaled. Since the UI thread is the STA in question, messages would need to be pumped to ensure that everything works properly.
The WM_DEVICECHANGE message can actually be sent to the window multiple times. So in the case where you call GetDrives directly, you effectively end up with recursive calls. Put a break point on the GetDrives call and then attach a device to fire the event.
The first time you hit the break point, everything in fine. Now press F5 to continue and you will hit the break point a second time. This time the call stack is something like:
[In a sleep, wait, or join]
DeleteMeWindowsForms.exe!DeleteMeWindowsForms.Form1.WndProc(ref System.Windows.Forms.Message m) Line 46 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) + 0x13 bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0x31 bytes
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam) + 0x64 bytes
[Native to Managed Transition]
[Managed to Native Transition]
mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext) + 0x2b bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) + 0x2d bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne() + 0x10 bytes
System.Management.dll!System.Management.MTAHelper.CreateInMTA(System.Type type) + 0x17b bytes
System.Management.dll!System.Management.ManagementPath.CreateWbemPath(string path) + 0x18 bytes
System.Management.dll!System.Management.ManagementClass.ManagementClass(string path) + 0x29 bytes
DeleteMeWindowsForms.exe!DeleteMeWindowsForms.Form1.GetDrives() Line 23 + 0x1b bytes C#
So effectively the window messages are being pumped to ensure the COM calls are properly marshalled, but this has the side effect of calling your WndProc and GetDrives again (as there are pending WM_DEVICECHANGE messages) while still in a previous GetDrives call. When you use BeginInvoke, you remove this recursive call.
Again, put a breakpoint on the GetDrives call and press F5 after the first time it's hit. The next time around, wait a second or two then press F5 again. Sometimes it will fail, sometimes it won't and you'll hit your breakpoint again. This time, your callstack will include three calls to GetDrives, with the last one triggered by the enumeration of the diskDriveList collection. Because again, the messages are pumped to ensure the calls are marshaled.
It's hard to pinpoint exactly why the MDA is triggered, but given the recursive calls it reasonable to assume the COM context may be torn down prematurely and/or an object is collected before the underlying COM object can be released.
Related
I'm using Ignite.NET 2.7.6 and sometimes it hangs on calling cache's methods like TryGet or MoveNext for cache's enumerator.
I have one server and multiple client nodes, the hang occurs on the client-side.
Typical call stack:
Apache.Ignite.Core.dll!Apache.Ignite.Core.Impl.Unmanaged.Jni.Env.CallVoidMethod(Apache.Ignite.Core.Impl.Unmanaged.Jni.GlobalRef obj, System.IntPtr methodId, long* argsPtr) Line 213 C#
Apache.Ignite.Core.dll!Apache.Ignite.Core.Impl.Unmanaged.UnmanagedUtils.TargetOutStream(Apache.Ignite.Core.Impl.Unmanaged.Jni.GlobalRef target, int opType, long memPtr) Line 145 C#
Apache.Ignite.Core.dll!Apache.Ignite.Core.Impl.PlatformJniTarget.OutStream(int type, System.Func readAction) Line 147 C#
Apache.Ignite.Core.dll!Apache.Ignite.Core.Impl.PlatformTargetAdapter.DoInOp(int type, System.Func action) Line 193 C#
Apache.Ignite.Core.dll!Apache.Ignite.Core.Impl.Cache.CacheEnumerator.MoveNext() Line 55 C#
Apache.Ignite.Core.dll!Apache.Ignite.Core.Impl.Cache.CacheEnumeratorProxy.MoveNext() Line 71 C#
AlphaLib.dll!Casino.Table.Enumerator.MoveNext() Line 503 C#
It hangs in CallVoidMethod. I tried to reproduce this on a simple project but failed.
This reproduces much more often if I start the client on the machine where the server node was started.
Any assumptions about why this happens?
ADDED
I inspected JVM state in case of hanging, here is the full stack: https://pastebin.com/v5HiuQWb
Looks like this thread is stuck:
"Thread-11" #148 prio=5 os_prio=0 tid=0x000001ae99665800 nid=0x34c4 in Object.wait() [0x00000050156bc000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at org.apache.ignite.internal.processors.cache.query.GridCacheQueryFutureAdapter.internalIterator(GridCacheQueryFutureAdapter.java:301)
- locked <0x00000005d494de98> (a org.apache.ignite.internal.processors.cache.query.GridCacheDistributedQueryFuture)
at org.apache.ignite.internal.processors.cache.query.GridCacheQueryFutureAdapter.next(GridCacheQueryFutureAdapter.java:158)
at org.apache.ignite.internal.processors.cache.query.GridCacheDistributedQueryManager$5.onHasNext(GridCacheDistributedQueryManager.java:642)
at org.apache.ignite.internal.util.GridCloseableIteratorAdapter.hasNextX(GridCloseableIteratorAdapter.java:53)
at org.apache.ignite.internal.util.lang.GridIteratorAdapter.hasNext(GridIteratorAdapter.java:45)
at org.apache.ignite.internal.processors.platform.cache.query.PlatformAbstractQueryCursor.processOutStream(PlatformAbstractQueryCursor.java:92)
at org.apache.ignite.internal.processors.platform.PlatformTargetProxyImpl.outStream(PlatformTargetProxyImpl.java:93)
It seems like this code hangs:
long waitTime = timeout == 0 ? Long.MAX_VALUE : timeout - (U.currentTimeMillis() - startTime);
if (waitTime <= 0) {
it = Collections.<R>emptyList().iterator();
break;
}
synchronized (this) {
try {
if (queue.isEmpty() && !isDone())
wait(waitTime); /* HERE!!! */
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IgniteCheckedException("Query was interrupted: " + qry, e);
}
}
I suppose that timeout is 0 in my case, so it waits infinitely, so it's possible to set it to a finite value. But it doesn't look like a good solution.
In our network, there is a Symantec protection system, that unexpectedly started closing ports that were used by Ignite. On both client and server sides. Furthermore, it was starting to close these ports after some event or time after launching - I didn't understand. I found it in the Symantec log.
After adding used ports to the white list the problem was solved.
I am writing a program in C# under Windows 10 to capture SysEx messages from MIDI devices. I'm using a callback function as follows:
private delegate void MidiInProc(
int handle,
uint msg,
int instance,
int param1,
int param2);
[DllImport("winmm.dll")]
private static extern int midiInOpen(
out int handle,
int deviceID,
MidiInProc proc,
int instance,
int flags);
private int hHandle;
public MidiInput(int deviceID)
{
MidiInProc midiInProc = MidiInProcess;
int hResult = midiInOpen(
out hHandle,
deviceID,
midiInProc,
0,
CALLBACK_FUNCTION | MIDI_IO_STATUS);
for (int i = 0; i < NUM_MIDIHDRS; ++i)
{
InitMidiHdr(i);
}
}
private void MidiInProcess(int hMidiIn, uint uMsg, int dwInstance, int dwParam1, int dwParam2)
{
switch (uMsg)
{
case MIM_OPEN:
break;
case MIM_CLOSE:
break;
case MIM_DATA:
QueueData(dwParam1);
break;
case MIM_MOREDATA:
QueueData(dwParam1);
break;
case MIM_LONGDATA:
QueueLongData((IntPtr)dwParam1);
break;
case MIM_ERROR:
throw new ApplicationException(string.Format("Invalid MIDI message: {0}", dwParam1));
case MIM_LONGERROR:
throw new ApplicationException("Invalid SysEx message.");
default:
throw new ApplicationException(string.Format("unexpected message: {0}", uMsg));
}
}
The InitMidiHdr method creates NUM_MIDIHDRS headers and buffers on the heap and passes their addresses to the driver with calls to MidiInPrepareHeader and MidiInAddBuffer. When SysEx data is received, the callback switches to the MIM_LONGDATA case and queues the buffer address to another thread which dequeues it, processes it, and then passes it back to the driver for further use via another call to MidiInAddBuffer.
Now, some programs do not use a separate thread, instead processing SysEx data on the callback's thread. From what I have read, this works most of the time, but not always, and is against the MSDN's advice: "Applications should not call any multimedia functions from inside the callback function[.]" This may not be a problem with contemporary drivers, but some users have, in the past, reported deadlocks when calling MidiInAddBuffer directly from the callback.
But...
When I use a worker thread to call MidiInAddBuffer, I can't think of a way to guarantee that it will keep up with calls to the callback. Sure, if the only thing the worker does is return the buffer, it will probably stay ahead of the callback, but relying on one thread to stay ahead of another without explicit synchronization is a bad practice. (Having the callback wait on a signal from the worker that it has returned the buffer doesn't work, as MidiInAddBuffer blocks when called from another thread until the callback returns, which leads to a deadlock if you condition its return on a return from MidiInAddBuffer in the worker thread.) Thus, it's possible in that scenario for the driver to run out of buffers while the MIDI device is still sending SysEx data. (Indeed, even in the scenario where the callback does all the processing itself, it too might fall behind, with the driver using up all of its buffers before the device stops sending SysEx data.)
I have found a couple of open-source projects that use a worker to call MidiInAddBuffer, but both appear to rely on the worker to stay ahead of calls to the callback. In fact, in one case, I added a 50ms sleep call to the worker, with the result being that it fell far behind the callback thread, which ultimately meant that only about half of the SysEx messages made it to the callback. Apparently, the driver doesn't buffer SysEx data internally and, when it has no buffers left to use, throws SysEx data away until it gets another buffer.
Now, memory being cheap and all that, one "solution" is to have a lot of buffers. My Behringer BCF2000, however, sends almost 500 distinct SysEx messages in a single dump, each in its own buffer. That's not an impossible number to supply, but it requires guesswork as to how many is really enough (and, given some of the exotic things people use SysEx messages to do, like pass around audio samples, such an approach could get unwieldy).
Alas, the MIM_LONGERROR case never gets called when my tests show that my code isn't keeping up, so that's no help.
So, here's my question: If my code is unable to keep up with the rate at which SysEx buffers are consumed by a MIDI device's driver and I end up missing some SysEx data, is there any way to at least detect that I have missed that data?
There is no reporting mechanism for missed SysEx buffers.
At the MIDI speed of 3125 bytes/s, the 50 ms delay corresponds to a buffer of 156 bytes; if the actual messages are shorter, you are guaranteed to fall behind.
But real code will not have such a consistent delay, so this is not a realistic test. Your threads might get random scheduling delays, but this is no problem as long as you have enough buffers queued. (And if some other code with higher priority prevents your code from being executed at all, there's nothing you can do anyway.)
I want to run some save routines when the computer suspends. Therefore I use the OnPowerChange-Event to detect when it suspends and resumes. Unfortunately me save routine needs 3-5 seconds to execute.
When I receive the suspend event the computer shuts down within 1-2 seconds and my routine isn't executed completely.
How can I prevent the suspend until my routine is finished?
SystemEvents.PowerModeChanged += OnPowerChange;
private void OnPowerChange(object s, PowerModeChangedEventArgs e)
{
switch (e.Mode)
{
case PowerModes.Resume:
switchEdifier(true);
break;
case PowerModes.Suspend:
switchEdifier(false);
break;
}
}
There are some unmanaged APIs that can help with this, specifically ShutdownBlockReasonCreate and ShutdownBlockReasonDestroy.
Its important to note that these two functions must be paired, when you call one, you have to make sure you call the other one (for example, in the event of an exception), otherwise the shutdown may be blocked indefinitely.
This will cause a dialog to show up telling the user what programs are blocking shutdown, and a reason for it. Its important that you get your work done quickly and get out, because the user has the option of hitting the "Force Shutdown" button, which they often use.
Here is an example using it:
[DllImport("user32.dll", SetLastError=true)]
static extern bool ShutdownBlockReasonCreate(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] string reason);
[DllImport("user32.dll", SetLastError=true)]
static extern bool ShutdownBlockReasonDestroy(IntPtr hWnd);
//The following needs to go in a Form class, as it requires a valid window handle
public void BlockShutdownAndSave()
{
//If calling this from an event, you may need to invoke on the main form
//because calling this from a thread that is not the owner of the Handle
//will cause an "Access Denied" error.
try
{
ShutdownBlockReasonCreate(this.Handle, "You need to be patient.");
//Do your saving here.
}
finally
{
ShutdownBlockReasonDestroy(this.Handle);
}
}
Short strings for the reason are encouraged as the user typically won't read long messages. Something that grabs attention, like "Saving data" or "Flushing changes to disk". Just be mindful of the "do it anyway I'm an impatient user" button.
im trying to do something on an app, that I know its name etc...(so I'm alredy casting findwindow and stuff)
For ex. I want to notify user when that window tries to gain focus.
I have mess around with wndproc yet I seem to not get it at all.
for ex. here is a code I found on stackoverflow and failed even executing it
public IntPtr WndProc(int hwnd, int msg, IntPtr wParam, IntPtr lParam)
{
if (msg == WM_NCACTIVATE)
{
SystemSounds.Beep.Play();
SystemSounds.Beep.Play();
SystemSounds.Beep.Play();
SystemSounds.Beep.Play();
SystemSounds.Beep.Play();
}
return IntPtr.Zero;
}
now the thing I dont understand is, there is int msg that I think stands for message. arent wndproc is the one that supposed to get it ? what is the point of giving it to wndproc ?
Second, executing this function. What do I do, check for message every 100 ms or are there event-type thing for it ?
Im really confused here and I'd appreciate little help here.
I'm afraid I don't entirely understand what you're asking here.
That WndProc function definition that you've found is not what it would look like in C#. Instead, you would override the WndProc member function of the Control class. All window messages are routed through this function. You would only override it if you wanted to process a message in an unusual way, to do something that the .NET Framework isn't already doing for you.
For example, for a Form, you would override WndProc like this:
public class MyForm : Form
{
// other code
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_NCACTIVATE:
{
SystemSounds.Beep.Play();
break;
}
base.WndProc(ref m); // proceed with default processing
}
}
}
Notice that the .NET Framework wraps all of the message information up into a Message structure, rather than passing 4 raw parameters to the function like the Win32 API does.
there is int msg that I think stands for message. arent wndproc is the one that supposed to get it ? what is the point of giving it to wndproc ?
The Message.Msg member corresponds to the int msg parameter in your function definition. This is the identifier of the window message that is to be processed. These are all defined inside of the Windows header files, and they generally begin with WM_. You can find the documentation for these messages on MSDN, which will tell you what they mean and when they are received. For example, the WM_NCACTIVATE message is sent to a window when its non-client area is being activated or inactivated.
The WndProc function is going to be called each time any message is received. The way you determine which message was received, and therefore which one you should be processing, is by switching on the value of the Message.Msg member (or, in your original example, the msg parameter).
Second, executing this function. What do I do, check for message every 100 ms or are there event-type thing for it ?
You don't have to check for anything. WndProc is a function, just like any other function, including those that you write yourself, which means that it only gets called when it should execute.
It is not itself an event, although the default processing inside of the WndProc function is what is responsible for raising the events you're familiar with in response to certain messages that it receives.
im trying to do something on an app, that I know its name etc...(so I'm alredy casting findwindow and stuff) For ex. I want to notify user when that window tries to gain focus.
I'm not exactly sure what this means, but you should look into the WM_ACTIVATEAPP message. This message is sent to a window whenever it is being activated and whenever it is being deactivated. In response to that message, you could choose to do whatever you like, including playing a sound. As the linked documentation indicates, the wParam parameter (found in the Message.WParam member) tells you whether your window is being activated or deactivated.
This is pretty much as advanced as it gets. It's extremely rare that you need to override the WndProc method when you're programming in WinForms. By doing so, you can do nearly anything, but there's almost always a better, simpler way to do things.
I'm attempting to pass messages between two applications - one of them is a plugin, and the other is a standalone configuration utility. When my plugin detects an event, I want to send a message to my utility and prompt the user to reconfigure.
The code I'm using is as follows:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SendMessage(IntPtr hwnd, uint Msg, IntPtr wParam, IntPtr lParam);
private const int MESSAGE_UNAUTH = 0x401;
[... misc logic here, function def, etc]
Process[] processes = Process.GetProcessesByName("MyConfigurationApplication");
if (processes.Length > 0)
{
foreach (Process p in processes)
{
SendMessage(p.MainWindowHandle, MESSAGE_UNAUTH, IntPtr.Zero, IntPtr.Zero);
}
}
And then in my receiving process, I have the following code (I also defined MESSAGE_UNAUTH in this class):
protected override void WndProc(ref Message message)
{
if (message.Msg == MESSAGE_UNAUTH)
{
MessageBox.Show("Message received");
}
base.WndProc(ref message);
}
Things I have already verified with the debugger:
The message is getting sent. All the code in the Sender, including the SendMessage call, is executing.
The message is not getting received (obviously).
The WndProc() function is not getting called at all when the message is sent. It is, however, getting called a whole bunch of times when the configuration utility is launched (I'm assuming this is Windows' behavior).
I've gone through enough online tutorials to need eyedrops, and as far as I know, everything here is syntax-correct and "proper," but for some reason, between when I send the message and when the receiver's WndProc() should be called, black magic is happening.
Any ideas would be greatly appreciated.
Update: Using Marshal.GetLastWin32Error(), I am getting an error #1400, which appears to correspond to an invalid window handle. However, I don't see why that would be the case, since the process was found and we entered the for each loop successfully. The one caveat I can think of is that my configuration utility is presented as a taskbar icon, and doesn't necessarily have a visible window at all times - would this prevent p.MainWindowHandle from being valid? If so, how can I work around this to pass a message to the process instead of the window?
Update: Process.MainWindowHandle is 0, so it looks like that is indeed the problem - when the form in my configuration utility is not visible, no valid window handler is returned, even though my utility icon is visible in the notification bar. Is there any way I can send a message to the process, or even to the taskbar icon?
You can try to enumerate all windows associated with the process. See How to enumerate all windows belonging to a particular process using .NET?
Depending on the .NET framework you are using, this will help resolve your issues.
There was a bug in the old .NET frameworks (2.0 I think) where calling to Process.MainWindowHandle when the process starts up returns 0. Any subsequent call will also result in a 0. This is due to caching the main window handle, which should have been fixed in .NET 3.0 and later.
You might also try giving full trust to your WndProc which might help. Something like:
[System.Security.Permissions.PermissionSet( System.Security.Permissions.SecurityAction.Demand, Name="FullTrust")]
protected override void WndProc(ref Message m)
{
//...
}
On a side note, if you can change your implementation then I strongly suggest you go for better inter process communication means such as sockets, TCPChannel (which I think is replaced by WCF), named pipes...
The message might not be sent, it might be blocked. See here: When a message is blocked by UIPI the last error, retrieved with GetLastError, is set to 5 (access denied).
Use Windows Registermessage in bothe sender and receiver end will resolve the problem
Problem was that the process I was sending the message to only existed as a tooltip icon and not as an active, open window. Turns out the windows message functionality is designed for window-to-window messages, not process-to-process messages.
Solution was aforementioned kludgy system of file IO handlers.