Using Microsoft Virtual Server from C#: CoSetProxyBlanket does nothing - c#

I'm attempting to write a couple of NAnt tasks for interacting with Microsoft Virtual Server 2005 R2 SP1, and I've lifted the code found on "Virtual PC Guy's WebLog", in the "Controlling Virtual Server through PowerShell" post.
It doesn't work: I always get a failure when calling CreateVirtualMachine:
System.Runtime.InteropServices.COMException (0x80070542): Either a required impersonation level was not provided, or the provided impersonation level is invalid. (Exception from HRESULT: 0x80070542)
at Microsoft.VirtualServer.Interop.VMVirtualServerClass.CreateVirtualMachine(String configurationName, String configurationPath)
My code is as follows:
var virtualServer = new VMVirtualServerClass();
SetSecurity(virtualServer);
var virtualMachine = virtualServer.CreateVirtualMachine("TEST",
#"D:\Virtual Server\TEST.vmc");
...where SetSecurity is defined as follows:
private static void SetSecurity(object dcomObject)
{
IntPtr pProxy = Marshal.GetIUnknownForObject(dcomObject);
int hr = CoSetProxyBlanket(pProxy,
RPC_C_AUTHN_DEFAULT,
RPC_C_AUTHZ_DEFAULT,
IntPtr.Zero,
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
RPC_C_IMP_LEVEL_IMPERSONATE,
IntPtr.Zero,
EOAC_DYNAMIC_CLOAKING);
Marshal.ThrowExceptionForHR(hr);
}
private const uint RPC_C_AUTHN_NONE = 0;
private const uint RPC_C_AUTHN_WINNT = 10;
private const uint RPC_C_AUTHN_DEFAULT = 0xFFFFFFFF;
private const uint RPC_C_AUTHZ_NONE = 0;
private const uint RPC_C_AUTHZ_DEFAULT = 0xFFFFFFFF;
private const uint RPC_C_AUTHN_LEVEL_DEFAULT = 0;
private const uint RPC_C_AUTHN_LEVEL_PKT_PRIVACY = 6;
private const uint RPC_C_IMP_LEVEL_IDENTIFY = 2;
private const uint RPC_C_IMP_LEVEL_IMPERSONATE = 3;
private const uint EOAC_NONE = 0;
private const uint EOAC_DYNAMIC_CLOAKING = 0x40;
private const uint EOAC_DEFAULT = 0x0800;
[DllImport("Ole32.dll")]
public static extern int CoSetProxyBlanket(IntPtr pProxy,
UInt32 dwAuthnSvc,
UInt32 dwAuthzSvc,
IntPtr pServerPrincName,
UInt32 dwAuthnLevel,
UInt32 dwImpLevel,
IntPtr pAuthInfo,
UInt32 dwCapabilities);
If I write a standalone program and add a call to CoInitializeSecurity, then it works. However, I don't want a standalone program -- I want a set of NAnt tasks (so a DLL), and I don't want to call CoInitializeSecurity, because there's no way of guaranteeing that some other NAnt task won't have called it already.
Has anyone got this working?

It's possible you're running into a fundamental problem with respect to using CoSetProxyBlanket from managed code. Unfortunately, there is no reiable way to interop with this method in managed code due to the way the CLR marshals interfaces.
Here are a couple of blogs entries that describe this problem
http://blogs.msdn.com/mbend/archive/2007/04/18/cosetproxyblanket-not-supported-from-managed-code.aspx
http://blogs.msdn.com/jaredpar/archive/2007/04/19/cosetproxyblanket-and-managed-code.aspx

For what it's worth, it looks like .NET 4.0 will add a new method GetObjectForIUnknownWithBlanket (under System.Runtime.InteropServices.Marshal) to help address this issue. From the (Beta) MSDN article:
GetObjectForIUnknownWithBlanket wraps
IUnknown in a unique managed object
and calls the CoSetProxyBlanket
function on all requested interfaces.
It ensures that a unique object is
returned instead of looking in the
cache to match the given IUnknown to
an existing object.
I haven't tried it yet, but it looks promising.
And by the way, great question and great accepted answer! I just encountered the same problem, and this was the only place I found a proper explanation.

Related

UWP: waveInOpen returns WAVERR_BADFORMAT

I am trying to record audio in UWP using Winmm.dll. After I execute waveInOpen method (https://msdn.microsoft.com/en-us/library/dd743847(v=vs.85).aspx) I always get WAVERR_BADFORMAT no matter the data I use (it also takes a long time abut 5s). My code looks as follows:
Recorder.cs:
Win32.WAVEFORMATEX waveFormatEx = new Win32.WAVEFORMATEX();
waveFormatEx.wFormatTag = (ushort)Win32.WaveFormatFlags.WAVE_FORMAT_PCM;
waveFormatEx.nChannels = 1;
waveFormatEx.nSamplesPerSec = 8000;
waveFormatEx.wBitsPerSample = 16;
waveFormatEx.nBlockAlign = 2;
waveFormatEx.nAvgBytesPerSec = 16000;
Win32.MMRESULT hr = Win32.waveInOpen(ref hWaveIn, deviceId, ref waveFormatEx, delegateWaveInProc, 0, (int)Win32.WaveProcFlags.CALLBACK_FUNCTION);
Win32.cs:
[StructLayout(LayoutKind.Sequential)]
public struct WAVEFORMATEX
{
public ushort wFormatTag;
public ushort nChannels;
public uint nSamplesPerSec;
public uint nAvgBytesPerSec;
public ushort nBlockAlign;
public ushort wBitsPerSample;
public ushort cbSize;
}
[DllImport("winmm.dll")]
public static extern MMRESULT waveInOpen(ref IntPtr hWaveIn, int deviceId, ref WAVEFORMATEX wfx, DelegateWaveInProc dwCallBack, int dwInstance, int dwFlags);
The same code with the same parameters works just fine in Windows Forms app (and executes in split second), but in UWP app it does't and i have no idea why. What is the correct format i could use in UWP?
While working with UWP projects, you could keep in mind: it is a limited subset of features (for the sake of security and cross-device compatibility). So, UWP project has nothing to do with Win32 API. And even if your code is compiling/running on the emulator, it will:
Fail on ARM devices (as they have no Win32 DLLs for sure)
Fail on app submission to Microsoft Store
So, if we're talking namely about audio, you have to consider WASAPI as it's 100% compatible with UWP https://msdn.microsoft.com/en-us/library/windows/desktop/dd371455(v=vs.85).aspx

Webbrowser control not working perfectly with proxies rotation

I am using many ipz and use them one after another some repeat after some time some with in seconds using this code:
string key = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
RegistryKey RegKey = Registry.CurrentUser.OpenSubKey(key, true);
RegKey.SetValue("ProxyServer", proxy);
RegKey.SetValue("ProxyEnable", 1);
webBrowser1.Navigate(customLinks[0].ToString());
The issue is its not always successful as i noticed many time.Suppose an ip is blocked so it takes the next one but i still see the block on the next one ,and even the next one.
So assuming its not taking proxy so fast etc?Maybe it needs to be refreshed.Kindly let me know how to implement this
Thank you
I got help from googling a lot , but do not remember the exact link:
Here is the code, i call the refresh function and pass proxy and it works 100 % everytime , anytime.
public struct Struct_INTERNET_PROXY_INFO
{
public int dwAccessType;
public IntPtr proxy;
public IntPtr proxyBypass;
};
[DllImport("wininet.dll", SetLastError = true)]
private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int lpdwBufferLength);
private void RefreshIESettings(string strProxy)
{
const int INTERNET_OPTION_PROXY = 38;
const int INTERNET_OPEN_TYPE_PROXY = 3;
Struct_INTERNET_PROXY_INFO struct_IPI;
// Filling in structure
struct_IPI.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
struct_IPI.proxy = Marshal.StringToHGlobalAnsi(strProxy);
struct_IPI.proxyBypass = Marshal.StringToHGlobalAnsi("local");
// Allocating memory
IntPtr intptrStruct = Marshal.AllocCoTaskMem(Marshal.SizeOf(struct_IPI));
// Converting structure to IntPtr
Marshal.StructureToPtr(struct_IPI, intptrStruct, true);
bool iReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY, intptrStruct, Marshal.SizeOf(struct_IPI));
}
Sounds like you need to set a single proxy in the browser, and implement that proxy yourself, such that it rotates requests to your proxy list.

Odd Errors from PInvoke struct/function

Im currently writing a C# wrapper for a C++ API, but a specific struct and a function that relies on this struct have been giving very strange errors when debugging.
C++ Struct:
typedef struct
{
unsigned __int handle;
char name[80];
unsigned int unique_ID;
} DeviceInfo;
Followed by this function:
int __stdcall get_device_info(DeviceInfo di[], const int length_of_di_array, int* p_numValidDevices);
The struct and function is imported as such:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DeviceInfo
{
public UInt32 handle;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 80)]
public String name;
public UInt32 unique_ID;
}
[DllImportAttribute("MyC++API.dll", EntryPoint = "get_device_info", CallingConvention = CallingConvention.StdCall)]
public static extern int get_device_info(ref DeviceInfo di, int length_of_di_array, ref numValidDevices);
The intended use of this struct and function is just to obtain some device info from the board Im accessing. Currently I do not have access to the function body in C++, so I can only assume it's working 100% (works fine in C++).
The issue is that when I use the function to run through an array of structs, it outputs the data I'm looking for, but also will begin to fail at runtime, giving me various error windows.
C# code:
static void Main()
{
int numValidDevices = 0; //initialize variable
DeviceInfo[] di = new DeviceInfo[16]; //max of 16 devices
for (int i = 0; i < numValidDevices; ++i) //sorts through all validated devices
{
rc = get_device_info(ref di[i], 16, ref numValidDevices); //accesses each device element and returns the data
Console.WriteLine("Handle: {0}\nName: {1}\nUnique ID: {2}", di[i].handle, di[i].name, di[i].unique_ID);
}
Console.ReadLine(); //stops console from closing prematurely
API_close(); //custom close function from the C++ API
}
Errors while debugging (information is still shown):
"An unhandled exception of type 'System.Threading.ThreadStateException' occurred in System.dll
Additional information: Thread has not been started."
"An unhandled exception of type 'System.ExecutionEngineException' occurred in mscorlib.dll"
Error while debugging (information is not shown, program fails to execute):
"An unhandled exception of type 'System.AccessViolationException' occurred in mscorlib.dll
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
When closing the console window:
"The instruction at '0x7c9113c0' referenced memory at '0x00000000'. The memory could not be 'written'." (sometimes says 'read' instead of 'written').
I've done a lot of research on PInvoke and came across the Microsoft InteropAssistant application, various stack overflow articles such as this one, and this post seems even closer to what Im doing, but I'm still digging into how to use the Marshal.CoTaskMemAlloc/Free, and see if it even will do anyhting...
Thus far what I have for my struct and function are correct, I've tried changing the struct to use an IntPtr but that does not return a di.name value and the di.unique_ID becomes jibberish (oddly enough the di.handle stays valid)
C# code:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DeviceInfo
{
public UInt32 handle;
IntPtr p_name;
public String name { get { return Marshal.PtrToStringAnsi(p_name); } }
public UInt32 unique_ID;
}
Intended output:
Handle: 3126770193
Name: DEVICE_A
Unique ID: 12345678
IntPtr output:
Handle: 3126770193
Name:
Unique ID: 1145128264
Oddly enough, using an IntPtr results in none of the errors above, and runs fine.
This leads me to believe the issue lies with marshaling over the C++ char to a string, but I'm not sure if the issue lies with the marshaling, memory management (there is none?), or something I'm not catching entirely.
Any and all feedback would be really appreciated, I've been stumped on this for a number of weeks now...
The exceptions you get indicate that the unmanaged code you are pinvoking is destroying the garbage collected heap. It isn't crystal why, but you don't give the pinvoke marshaller much of a chance to do the Right Thing. It cannot properly pin the array. Start by declaring the function properly, it takes an array so declare one:
[DllImportAttribute("MyC++API.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int get_device_info(
DeviceInfo[] di,
int length_of_di_array,
out int p_numValidDevices
);
Your first declaration of DeviceInfo is correct, the 2nd isn't since the string isn't a pointer.
Something's not adding up, here. It's not clear to me how the function is supposed to be called.
In particular, this declaration:
int __stdcall get_device_info(DeviceInfo di[], const int length_of_di_array, int* p_numValidDevices);
doesn't match how you're using it:
[DllImportAttribute("MyC++API.dll", EntryPoint = "get_device_info", CallingConvention = CallingConvention.StdCall)]
public static extern int get_device_info(ref DeviceInfo di, const int length_of_di_array, int* p_numValidDevices);
...
DeviceInfo[] di = new DeviceInfo[16]; //max of 16 devices
for (int i = 0; i < numValidDevices; ++i) //sorts through all validated devices
{
rc = get_device_info(ref di[i], 16, ref numValidDevices); //accesses each device element and returns the data
}
You're telling it that the array length is 16, starting at index i, which is wrong. Did you mean to only pass one element of the array at a time?
DeviceInfo[] di = new DeviceInfo[16]; //max of 16 devices
for (int i = 0; i < numValidDevices; ++i) //sorts through all validated devices
{
rc = get_device_info(ref di[i], 1, ref numValidDevices); //accesses each device element and returns the data
}
Or did you mean to pass the entire array once?
DeviceInfo[] di = new DeviceInfo[16]; //max of 16 devices
rc = get_device_info(ref di[0], 16, ref numValidDevices); //accesses each device element and returns the data
for (int i = 0; i < numValidDevices; ++i) //sorts through all validated devices
{
Console.WriteLine(...);
}
P.S. I would consider changing your p/invoke declaration to be:
[DllImportAttribute("MyC++API.dll", EntryPoint = "get_device_info", CallingConvention = CallingConvention.StdCall)]
public static extern int get_device_info(
[In, Out] [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] DeviceInfo[] di,
int length_of_di_array,
ref int p_numValidDevices);
So, as pointed out in the replies below, I had two problems:
1. I wasn't calling my DllImport correctly, the way I had it was in an attempt to hack together an output, in doing so I screwed up the memory allocation to the array of structs.
2. I tried to hack together an output and screwed up the code even more (tried to pass in the DeviceInfo array di as a single element di[number] instead of as a whole).
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DeviceInfo
{
public UInt32 handle;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 80)]
public String name;
public UInt32 unique_ID;
}
[DllImportAttribute("MyC++API.dll", EntryPoint = "get_device_info", CallingConvention = CallingConvention.StdCall)]
public static extern int get_device_info(
[In, Out] [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] DeviceInfo[] di,
int length_of_di_array,
ref int p_numValidDevices);
static void Main()
{
int numValidDevices = 0;
DeviceInfo[] di = new DeviceInfo[16];
get_device_info(di, 16, ref numValidDevices);
for (int i = 0; i < numValidDevices; ++i)
{
Console.WriteLine("Handle: {0}\nName: {1}\nUnique ID: {2}", di[i].handle, di[i].name, di[i].unique_ID);
}
Console.ReadLine();
API_close();
}

Programmatically install Certificate Revocation List (CRL)

I need to download and install about 50 CRLs once a week and install them on several Windows servers. Downloading is the easy part, is there a way I could script the CRL import process?
Here is my final source (slightly scrubbed for the public) - but should work. I won't change the accepted answer, but I do hope this helps (as does upvoting the question and answers!).
Note: This will import both a CRL or a regular certificate into the LOCAL MACHINE Trusted Root store. Changing the below CERT_SYSTEM_STORE_LOCAL_MACHINE to CERT_SYSTEM_STORE_CURRENT_USER in the call CertOpenStore will change it to work for the Current User store.
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication2
{
class Program
{
public struct CRYPTUI_WIZ_IMPORT_SRC_INFO
{
public Int32 dwSize;
public Int32 dwSubjectChoice;
[MarshalAs(UnmanagedType.LPWStr)]public String pwszFileName;
public Int32 dwFlags;
[MarshalAs(UnmanagedType.LPWStr)]public String pwszPassword;
}
[DllImport("CryptUI.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean CryptUIWizImport(
Int32 dwFlags,
IntPtr hwndParent,
IntPtr pwszWizardTitle,
ref CRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc,
IntPtr hDestCertStore
);
[DllImport("CRYPT32.DLL", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CertOpenStore(
int storeProvider,
int encodingType,
IntPtr hcryptProv,
int flags,
String pvPara
);
public const Int32 CRYPTUI_WIZ_IMPORT_SUBJECT_FILE = 1;
public const Int32 CRYPT_EXPORTABLE = 0x00000001;
public const Int32 CRYPT_USER_PROTECTED = 0x00000002;
public const Int32 CRYPTUI_WIZ_NO_UI = 0x0001;
private static int CERT_STORE_PROV_SYSTEM = 10;
private static int CERT_SYSTEM_STORE_CURRENT_USER = (1 << 16);
private static int CERT_SYSTEM_STORE_LOCAL_MACHINE = (2 << 16);
static void Main(string[] args)
{
if (args.Length != 1)
{
Console.WriteLine("Usage: certimp.exe list.crl");
Environment.ExitCode = 1;
}
else
{
IntPtr hLocalCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
IntPtr.Zero,
CERT_SYSTEM_STORE_LOCAL_MACHINE,
"ROOT"
);
CRYPTUI_WIZ_IMPORT_SRC_INFO importSrc = new CRYPTUI_WIZ_IMPORT_SRC_INFO();
importSrc.dwSize = Marshal.SizeOf(importSrc);
importSrc.dwSubjectChoice = CRYPTUI_WIZ_IMPORT_SUBJECT_FILE;
importSrc.pwszFileName = args[0];
importSrc.pwszPassword = null;
importSrc.dwFlags = CRYPT_EXPORTABLE | CRYPT_USER_PROTECTED;
if (!CryptUIWizImport(
CRYPTUI_WIZ_NO_UI,
IntPtr.Zero,
IntPtr.Zero,
ref importSrc,
hLocalCertStore
))
{
Console.WriteLine("CryptUIWizImport error " + Marshal.GetLastWin32Error());
Environment.ExitCode = -1;
}
}
}
}
}
I don't know a way to do it via script.
Can you write C code? If I understand what you want to do, you will use the CryptUiWizImport function, and the CRYPTUI_WIZ_IMPORT_SRC_INFO structure.
Here's a sample of code that installs a Cert; the corresponding CRL import is similar.
Addendum:
This post points out that Win32 APIs (such as CryptUiWizImport) are not directly accessible from PowerShell, and then describes a possible workaround: from within the PowerShell script, dynamically generate and compile C# code that does the P/Invoke stuff, and then run the resulting assembly. This would allow you to do the CryptUiWizImport strictly from a powershell script, although it would be a pretty exotic one.
Hm. Is there any reason not to use the certutil.exe utility? I can import a Certificate Revocation List into the appropriate store by running the following command:
certutil -addstore CA <FileName>.crl
In Powershell there is a Cert: provider which represents the certificate store. Manipulating it is done via the standard cmdlets so you might be able to integrate a revocation list there somewhere. I just don't know enough about how Windows handles certificates to be of any further help here.
We have to use only Win32 Apis to do this. There is no firstclass C# system APIs to do this. Refer https://stackoverflow.com/a/67814697/3671594

P/Invoking CreateToolhelp32Snapshot failing in Compact Framework

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));

Categories