P/Invoking CreateToolhelp32Snapshot failing in Compact Framework - c#

Hey, im doing a little app for my smart phone, using Windows Mobile 6. I'm trying to get all currently running processec, but method CreateToolhelp32Snapshot always returns -1. So now im stuck. I tried to get error with invoking GetLastError() method, but that method returns 0 value.
Here is a snippet of my code.
private const int TH32CS_SNAPPROCESS = 0x00000002;
[DllImport("toolhelp.dll")]
public static extern IntPtr CreateToolhelp32Snapshot(uint flags,
uint processid);
public static Process[] GetProcesses()
{
ArrayList procList = new ArrayList();
IntPtr handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if ((int)handle > 0)
{
try
{
PROCESSENTRY32 peCurr;
PROCESSENTRY32 pe32 = new PROCESSENTRY32();
// get byte array to pass to API call
byte[] peBytes = pe32.ToByteArray();
// get the first process
int retval = Process32First(handle, peBytes);

First, your handle check is wrong. It's common for the high bit to be on in a handle, causing it to look like a negative number when cast to a signed int. You should be checking that is isn't NULL (0) or INVALID_HANDLE_VALUE (-1 / 0xffffffff).
You shouldn't be "invoking GetLastError" but calling Marshal.GetLastWin32Error()
You've not set the SetLastError attribute in the P/Invoke declaration. In C# it defaults to false, in VB it defaults to true.
Where's your PROCESS32 implementation? The docs clearly state that the dwLength member must be set before the call and it's not clear here if that's happening.
As a side note, the Smart Device Framework's OpenNETCF.ToolHelp namespace has all of this implemented and working (in case you'd rather not reinvent the wheel).

Instead of
CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
use
private const int TH32CS_SNAPNOHEAPS = 0x40000000;
CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0);
By default CreateToolhelp32Snapshot will try to snapshot the heaps and that can cause an out of memory error.
Found this at https://social.msdn.microsoft.com/Forums/en-US/e91d845d-d51e-45ad-8acf-737e832c20d0/createtoolhelp32snapshot-windows-mobile-5?forum=vssmartdevicesnative and it solved my problem.

If you're not seeing valid "last error" information, perhaps you might need to add the "SetLastError" attribute on the API's DllImport attribute (MSDN reference with code examples). According to the documentation of this attribute, you should set SetLastError to...
...true to indicate that the callee will
call SetLastError; otherwise, false.
The default is false.
The runtime marshaler calls
GetLastError and caches the value
returned to prevent it from being
overwritten by other API calls. You
can retrieve the error code by calling
GetLastWin32Error
As for the API failure you're seeing, I don't spot anything obvious offhand; the code you have seems very similar to the sample code here.

This is the proper implementation based on the MSDN documentation
private const int INVALID_HANDLE_VALUE = -1;
[Flags]
private enum SnapshotFlags : uint
{
HeapList = 0x00000001,
Process = 0x00000002,
Thread = 0x00000004,
Module = 0x00000008,
Module32 = 0x00000010,
Inherit = 0x80000000,
All = 0x0000001F,
NoHeaps = 0x40000000
}
[DllImport("toolhelp.dll"]
private static extern IntPtr CreateToolhelp32Snapshot(SnapshotFlags dwFlags, int th32ProcessID);
[StructLayout(LayoutKind.Sequential)]
public struct PROCESSENTRY32
{
public uint dwSize;
public uint cntUsage;
public uint th32ProcessID;
public IntPtr th32DefaultHeapID;
public uint th32ModuleID;
public uint cntThreads;
public uint th32ParentProcessID;
public int pcPriClassBase;
public uint dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szExeFile;
};
IntPtr hSnap = CreateToolhelp32Snapshot(SnapshotFlags.Process, 0);
if (hSnap.ToInt64() != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 procEntry = new PROCESSENTRY32();
procEntry.dwSize = (uint)Marshal.SizeOf(typeof(PROCESSENTRY32));
if (Process32First(hSnap, ref procEntry))
{
do
{
//do whatever you want here
} while (Process32Next(hSnap, ref procEntry));
}
}
CloseHandle(hSnap);
Most importantly is this line, because you must set the size of the procEntry:
procEntry.dwSize = (uint)Marshal.SizeOf(typeof(PROCESSENTRY32));

Related

Setting all checkboxes in a listView in another application with winAPI

So I have this code to set all items (or even a single item i stated the code for item number 3) for a listview in another application using sendmessage, I already managed to successfully get the item window handle of the listview and got the item count right but when i use setitemstate the other application gives me error and closes (given that there is another application I have that do this job just fine but i don't have its source code)
this is my code :
if (windowName.Contains("Invite to Room")) {
IntPtr hwndChild0 = FindWindowEx(hWnd, IntPtr.Zero, "SysListView32", "");
int itemCount = SendMessage(hwndChild0, LVM_GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);
LV_ITEM lvItem = new LV_ITEM();
lvItem.Index = 3;
lvItem.SubIndex = 2;
lvItem.TextLength = 50;
lvItem.Mask = LVIF_STATE;
lvItem.State = LVIS_SELECTED;
lvItem.StateMask = LVIS_SELECTED;
SendMessage(hwndChild0, LVM_SETITEMSTATE, 3, IntPtr.Zero);
}
this is my LV_ITEM structure
public struct LV_ITEM
{
public uint Mask;
public int Index;
public int SubIndex;
public int State;
public IntPtr StateMask;
public string Text;
public int TextLength;
public int ImageIndex;
public IntPtr LParam;
}
and this is the declaration of the used (sendmessage and setitemstate)
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, string lParam);
private const uint LVM_FIRST = 0x1000;
private const uint LVM_SETITEMSTATE = (LVM_FIRST + 43);
any help with this?
Edit :
the application error has a log file that said the following message :
"The thread tried to read from or write to a virtual address for which it doesn't have the appropriate access"
Some messages only use WPARAM, LPARAM and return LRESULT to pass data around, like LVM_GETITEMCOUNT that worked for you.
Other messages use pointers to some data structure to be used or filled, like LVM_SETITEMSTATE. It expects a pointer to pre-filled LV_ITEM structure in LPARAM, while you pass IntPtr.Zero - so you cause an access violation in that other application trying to dereference that zero pointer.
However, you can't just simply pass the pointer to your lvItem, as it wouldn't make any sense in another process. You need to allocate a memory for that structure in the second process, initialize it, send you message and read that memory back (if you expect any response).

C#: How to tell if an EXE has an icon?

I'm looking for a way to tell whether or not an EXE file contains an application icon. From the answer here, I tried this:
bool hasIcon = Icon.ExtractAssociatedIcon(exe) != null;
But this seems to work even if the EXE has no icon. Is there a way to detect this in .NET?
edit: I'm OK with solutions involving P/Invoke.
You can get the IDI_APPLICATION icon through SystemIcons.Application property from SystemIcons class
if (Icon.ExtractAssociatedIcon(exe).Equals(SystemIcons.Application))
{
...
}
See MSDN for more details.
Try this. Define your pinvoke like this:
[DllImport("user32.dll")]
internal static extern IntPtr LoadImage(IntPtr hInst, IntPtr name, uint type, int cxDesired, int cyDesired, uint fuLoad);
[DllImport("kernel32.dll")]
static extern bool EnumResourceNames(IntPtr hModule, int dwID, EnumResNameProcDelegate lpEnumFunc, IntPtr lParam);
delegate bool EnumResNameProcDelegate(IntPtr hModule, IntPtr lpszType, IntPtr lpszName, IntPtr lParam);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr LoadLibraryEx(string name, IntPtr handle, uint dwFlags);
private const int LOAD_LIBRARY_AS_DATAFILE = 0x00000002;
private const int LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020;
private const int IMAGE_ICON = 1;
private const int RT_GROUP_ICON = 14;
Then you can write a function like this:
static bool HasIcon(string path)
{
// This loads the exe into the process address space, which is necessary
// for LoadImage / LoadIcon to work note, that LOAD_LIBRARY_AS_DATAFILE
// allows loading a 32-bit image into 64-bit process which is otherwise impossible
IntPtr moduleHandle = LoadLibraryEx(path, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
if (moduleHandle == IntPtr.Zero)
{
throw new ApplicationException("Cannot load executable");
}
IntPtr index = IntPtr.Zero;
bool hasIndex = false;
bool enumerated = EnumResourceNames(moduleHandle, RT_GROUP_ICON, (module, type, name, param) =>
{
index = name;
hasIndex = true;
// Only load first icon and bail out
return false;
}, IntPtr.Zero);
if (!enumerated || !hasIndex)
{
return false;
}
// Strictly speaking you do not need this you can return true now
// This is to demonstrate how to access the icon that was found on
// the previous step
IntPtr result = LoadImage(moduleHandle, index, IMAGE_ICON, 0, 0, 0);
if (result == IntPtr.Zero)
{
return false;
}
return true;
}
It has added bonus that if you want to, after LoadImage you can load the icon with
Icon icon = Icon.FromHandle(result);
and do whatever you want with that.
Important note: I have not done any clean up in the function, so you cannot use it as is, you'll leak handles/memory. Proper clean up is left as an exercise for the reader. Read the description of every of the winapi function used in MSDN and call corresponding clean up functions as needed.
An alternate way using shell32 api can be found here, although I don't know if it has the same problem you encountered.
Also, old, but still very relevant article: https://msdn.microsoft.com/en-us/library/ms997538.aspx

Trouble calling SystemParametersInfo

Recently I've been trying to call the SystemParametersInfo method from managed code, without any success.
The problem is that, after calling the method, the method returns false (indicating failure), however GetLastError (retrieved by Marshal.GetLastWin32Error()) is 0.
I tried to invoke the method from C++ as a test (with the exact same parameters), and it works completely fine from there.
The P/Invoke declaration of the method is this:
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SystemParametersInfo(SPI uiAction, int uiParam, ref STICKYKEYS pvParam, SPIF fWinIni);
internal struct STICKYKEYS
{
public int cbSize;
public int dwFlags;
}
And the invocation is as follows:
NativeMethods.STICKYKEYS stickyKeys = default(NativeMethods.STICKYKEYS);
bool result = NativeMethods.SystemParametersInfo(NativeMethods.SPI.SPI_GETSTICKYKEYS, StickyKeysSize, ref stickyKeys, 0);
int error = Marshal.GetLastWin32Error();
The SPI.SPI_GETSTICKYKEYS is0x003A (as seen on MSDN).
Here the result is false, and the error returned is 0.
Also this is complied as a 64-bit executable if that matters.
I'm completely at my wit's end, do you have any idea what I might be doing wrong?
As GSerg pointed it out to me, my issue was that I need to pass in the size of the struct both directly as a parameter, and as the cbSize member of the struct that I passed in by reference.
The correct code is:
int stickyKeysSize = Marshal.SizeOf(typeof (NativeMethods.STICKYKEYS));
NativeMethods.STICKYKEYS stickyKeys = new NativeMethods.STICKYKEYS {cbSize = stickyKeysSize, dwFlags = 0};
bool result = NativeMethods.SystemParametersInfo(NativeMethods.SPI.SPI_GETSTICKYKEYS, stickyKeysSize, ref stickyKeys, 0);
if (!result) throw new System.ComponentModel.Win32Exception();
return stickyKeys;

When did SECURITY_ATTRIBUTES change and why?

I have some code that uses P/Invoke to launch a process and capture the standard output. (The story of why we did this using P/Invoke instead of System.Diagnostics.Process is long and convoluted; suffice it to say it's a requirement.) It's been working in production under heavy load for nearly a year, and the tests that exercise it have always passed.
This morning though I ran the tests, and they failed. I can't be certain when I last ran the tests prior to this morning (5/15/2014), but I believe it was 4/24/2014. The tests passed then, but failed this morning. I was getting the "PInvokeStackImbalance" error message, so I did some research, and eventually realized the signature of one of the structs used by the extern method (CreatePipe in this instance) was incorrect. I changed it, and the tests started passing again.
I'm happy to have found the fix, but I'm concerned about deployment. Why did the signature of the struct change? I haven't upgraded my OS or anything - I was running Windows 7 x64 on 4/24, and I'm still running it now. (The deployment environment is Windows Server 2012.) I've installed (and uninstalled) a few apps since then, but they've been light-weight 3rd-party tools, not Microsoft or system components. I assume a Windows Update hotfix is responsible, but I can't figure out which one.
To be clear, in my own code, all I changed was this:
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public UInt32 nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
to this:
[StructLayout(LayoutKind.Sequential)]
internal class SECURITY_ATTRIBUTES
{
public int nLength = 12;
public IntPtr lpSecurityDescriptor = IntPtr.Zero;
public bool bInheritHandle;
}
I need to be sure that the change I made to get the code working on my machine isn't going to break the app when I deploy to production. Does anyone know how to identify what necessitated the change and how to determine whether the production environment does or does not require it?
EDIT:
Here is the code that opens the pipe for the standard output:
private PipeInfo CreatePipe()
{
PipeInfo pipeInfo = new PipeInfo();
SafeFileHandle safeFileHandle = null;
try
{
Native.SECURITY_ATTRIBUTES pipeAttributes = new Native.SECURITY_ATTRIBUTES();
pipeAttributes.bInheritHandle = true;
if (!Native.CreatePipe(out safeFileHandle, out pipeInfo.ChildHandle, pipeAttributes, 0) || safeFileHandle.IsInvalid || pipeInfo.ChildHandle.IsInvalid)
{
throw new Win32Exception();
}
if (!Native.DuplicateHandle(new HandleRef(this, Native.GetCurrentProcess()), safeFileHandle, new HandleRef(this, Native.GetCurrentProcess()), out pipeInfo.ParentHandle, 0, false, 2))
{
throw new Win32Exception();
}
}
finally
{
if (safeFileHandle != null && !safeFileHandle.IsInvalid)
{
safeFileHandle.Close();
}
}
return pipeInfo;
}
I can't exactly take credit for this code, I largely lifted it from the .NET Reference Source
Just to be clear on timeline:
May 2013 - write the CreatePipe code with the first version of SECURITY_ATTRIBUTES
June 2013 - deploy; code has been running successfully ever since
April 2014 - without any changes being made, code starts throwing stack imbalance error
May 2014 - I change to the second version of SECURITY_ATTRIBUTES and the error goes away
We encountered this problem on x64 and this post was the top result in our search. We were using the magic 12 for nLength just like your solution which we got from the C# source for process: https://referencesource.microsoft.com/#System/services/monitoring/system/diagnosticts/Process.cs
[StructLayout(LayoutKind.Sequential)]
internal class SECURITY_ATTRIBUTES {
#if !SILVERLIGHT
// We don't support ACL's on Silverlight nor on CoreSystem builds in our API's.
// But, we need P/Invokes to occasionally take these as parameters. We can pass null.
public int nLength = 12;
public SafeLocalMemHandle lpSecurityDescriptor = new SafeLocalMemHandle(IntPtr.Zero, false);
public bool bInheritHandle = false;
#endif // !SILVERLIGHT
}
It turns out CreatePipe expects a pointer, from the docs:
lpPipeAttributes
A pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpPipeAttributes is NULL, the handle cannot be inherited.
The solution is detailed in this stackoverflow post. It works for both x86 and x64. Our code is below based on that stack overflow post and the process source (with using DWORD = System.UInt32; at the top).
internal static class NativeMethods
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CreatePipe(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe,
IntPtr lpPipeAttributes, int nSize);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, SafeHandle hSourceHandle,
IntPtr hTargetProcess, out SafeFileHandle targetHandle, int dwDesiredAccess,
bool bInheritHandle, int dwOptions);
[StructLayout(LayoutKind.Sequential)]
public struct PIPE_SECURITY_ATTRIBUTES
{
public DWORD nLength;
public IntPtr lpSecurityDescriptor;
[MarshalAs(UnmanagedType.Bool)]
public bool bInheritHandle;
}
public static void CreatePipe(out SafeFileHandle parentHandle, out SafeFileHandle childHandle, bool parentInputs)
{
PIPE_SECURITY_ATTRIBUTES lpPipeAttributes = new PIPE_SECURITY_ATTRIBUTES();
lpPipeAttributes.nLength = (DWORD)Marshal.SizeOf(lpPipeAttributes);
lpPipeAttributes.bInheritHandle = true;
lpPipeAttributes.lpSecurityDescriptor = IntPtr.Zero;
IntPtr attr = Marshal.AllocHGlobal(Marshal.SizeOf(lpPipeAttributes));
Marshal.StructureToPtr(lpPipeAttributes, attr, true);
SafeFileHandle hWritePipe = null;
try
{
if (parentInputs)
CreatePipeWithSecurityAttributes(out childHandle, out hWritePipe, attr, 0);
else
CreatePipeWithSecurityAttributes(out hWritePipe, out childHandle, attr, 0);
if (!DuplicateHandle(GetCurrentProcess(), hWritePipe, GetCurrentProcess(), out parentHandle, 0, false, 2))
throw new Exception();
}
finally
{
if ((hWritePipe != null) && !hWritePipe.IsInvalid)
{
hWritePipe.Close();
}
}
}
public static void CreatePipeWithSecurityAttributes(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe,
IntPtr lpPipeAttributes, int nSize)
{
hReadPipe = null;
if ((!CreatePipe(out hReadPipe, out hWritePipe, lpPipeAttributes, nSize) || hReadPipe.IsInvalid) || hWritePipe.IsInvalid)
throw new Exception();
}
}

WinUSB_Initialize function occurs INVALID_FUNCTION (0x1) Error

Why does the WinUSB_Initialize function occur INVALID_FUNCTION (0x1) Error?
This is a function from the winusb.dll which returns an interface handle.
I would like to get an Interface handle.
I already have a Device handle.
internal struct devInfo
{
internal SafeFileHandle deviceHandle;
internal IntPtr winUsbHandle;
internal Byte bulkInPipe;
internal Byte bulkOutPipe;
internal Byte interruptInPipe;
internal Byte interruptOutPipe;
internal UInt32 devicespeed;
}
internal const Int32 FILE_ATTRIBUTE_NORMAL = 0X80;
internal const Int32 FILE_FLAG_OVERLAPPED = 0X40000000;
internal const Int32 FILE_SHARE_READ = 1;
internal const Int32 FILE_SHARE_WRITE = 2;
internal const UInt32 GENERIC_READ = 0X80000000;
internal const UInt32 GENERIC_WRITE = 0X40000000;
internal const Int32 OPEN_EXISTING = 3;
[DllImport("winusb.dll", SetLastError = true)]
internal static extern Boolean WinUsb_Initialize
(SafeFileHandle DeviceHandle,
ref IntPtr InterfaceHandle);
internal devInfo myDevInfo; // = new devInfo();
public IntPtr Get_WinUSB_handle()
{
Guid myGuid = Get_HID_GUID();
IntPtr deviceInfoSet = Get_Device_Info_Set(myGuid);
SP_DEVICE_INTERFACE_DATA MyDeviceInterfaeData = Get_Device_Interface_Data(deviceInfoSet, myGuid);
IntPtr detailDataBuffer = Get_Structure_with_Device_PathName(deviceInfoSet, ref MyDeviceInterfaeData);
string devicePathName = Get_Device_PathName(detailDataBuffer);
myDevInfo.deviceHandle= CreateFile(devicePathName,
(GENERIC_WRITE | GENERIC_READ),
FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0);
Boolean success;
success = WinUsb_Initialize(myDevInfo.deviceHandle, ref myDevInfo.winUsbHandle);
System.Console.WriteLine(Marshal.GetLastWin32Error());
System.Console.WriteLine(success);
return myDevInfo.winUsbHandle;
}
success = WinUsb_Initialize(...);
System.Console.WriteLine(Marshal.GetLastWin32Error());
This kind of error checking is wrong. It is only valid to call Marshal.GetLastWin32Error() when a winapi function failed. So a rock-hard requirement is to check success first. Calling GetLastWin32Error() anyway produces an arbitrary garbage value if the function actually succeeded. ERROR_INVALID_FUNCTION certainly has a high garbage value.
The code is also fairly broken when there actually is an error, it doesn't nearly make enough noise and the client code can easily ignore the invalid handle value. Proper code is:
bool success = WinUsb_Initialize(...);
if (!success) throw new System.ComponentModel.Win32Exception();
The exception constructor already calls Marshal.GetLastWin32Error() and will produce an appropriate localized error message.
I believe you are connecting to a device that is not actually using winusb.sys as one of its drivers. To other people who might read this, you can check if a device uses winusb.sys by double-clicking it in the Device Manager, going to the "Driver" tab, and clicking on "Driver Details". If you don't see winusb.sys there then this is not a WinUSB device.
To have a WinUSB device, you need to write a proper INF file and then tell Windows to use it one way or another.
It looks like you are trying to access an HID. Instead of using WinUSB I would recommend HIDAPI.

Categories