Working Example of Createjobobject/Setinformationjobobject Pinvoke in .Net

Working example of CreateJobObject/SetInformationJobObject pinvoke in .net?

This can be little bit late, but still.

I tried all of the examples here, but no one was working for me in 32 and 64 bit mode simultaneously. Finally, I was required to examine all the signatures myself and create corresponding PInvoke routines. I think, somebody else could find this helpful.

Disclaimer: the solution is based on Matt Howells' answer.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace JobManagement
{
public class Job : IDisposable
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr CreateJobObject(IntPtr a, string lpName);

[DllImport("kernel32.dll")]
static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);

private IntPtr handle;
private bool disposed;

public Job()
{
handle = CreateJobObject(IntPtr.Zero, null);

var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION
{
LimitFlags = 0x2000
};

var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
BasicLimitInformation = info
};

int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length);
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);

if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length))
throw new Exception(string.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error()));
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

private void Dispose(bool disposing)
{
if (disposed)
return;

if (disposing) { }

Close();
disposed = true;
}

public void Close()
{
CloseHandle(handle);
handle = IntPtr.Zero;
}

public bool AddProcess(IntPtr processHandle)
{
return AssignProcessToJobObject(handle, processHandle);
}

public bool AddProcess(int processId)
{
return AddProcess(Process.GetProcessById(processId).Handle);
}

}

#region Helper classes

[StructLayout(LayoutKind.Sequential)]
struct IO_COUNTERS
{
public UInt64 ReadOperationCount;
public UInt64 WriteOperationCount;
public UInt64 OtherOperationCount;
public UInt64 ReadTransferCount;
public UInt64 WriteTransferCount;
public UInt64 OtherTransferCount;
}

[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
public Int64 PerProcessUserTimeLimit;
public Int64 PerJobUserTimeLimit;
public UInt32 LimitFlags;
public UIntPtr MinimumWorkingSetSize;
public UIntPtr MaximumWorkingSetSize;
public UInt32 ActiveProcessLimit;
public UIntPtr Affinity;
public UInt32 PriorityClass;
public UInt32 SchedulingClass;
}

[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public UInt32 nLength;
public IntPtr lpSecurityDescriptor;
public Int32 bInheritHandle;
}

[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
public IO_COUNTERS IoInfo;
public UIntPtr ProcessMemoryLimit;
public UIntPtr JobMemoryLimit;
public UIntPtr PeakProcessMemoryUsed;
public UIntPtr PeakJobMemoryUsed;
}

public enum JobObjectInfoType
{
AssociateCompletionPortInformation = 7,
BasicLimitInformation = 2,
BasicUIRestrictions = 4,
EndOfJobTimeInformation = 6,
ExtendedLimitInformation = 9,
SecurityLimitInformation = 5,
GroupInformation = 11
}

#endregion

}

Unusual ERROR_BAD_LENGTH while setting job memory limits in C#

As it turns out, the object structure in the given example isn't correct for my system. I don't know if this is simply an issue with the example that isn't found by the path its author takes, or if something has changed about the architecture.

All of the working code I've found and made uses 4 bytes for LimitFlags when running in 32bit mode, and 8 bytes when running in 64bit mode.

Pinvoke CreateProcess input/output from file

Based on comments.

  1. Set startupInfo.dwFlags to 0x00000100
  2. Add new function CreateFile:

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr CreateFile(string lpFileName, DesiredAccess dwDesiredAccess, uint dwShareMode, ref SecurityAttributes lpSecurityAttributes, CreationDisposition dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
  3. Create input/output handlers:

    var input = Pinvoke.CreateFile(inputFile, DesiredAccess.GENERIC_READ, 0, ref securityAttributes,
    CreationDisposition.OPEN_EXISTING, 0, IntPtr.Zero);

    var output = Pinvoke.CreateFile(outputFile, DesiredAccess.GENERIC_WRITE, 0, ref securityAttributes,
    CreationDisposition.CREATE_NEW, 0, IntPtr.Zero);

    startupInfo.hStdInput = input;
    startupInfo.hStdOutput = output;

    ...

    public enum DesiredAccess : uint
    {
    GENERIC_WRITE = 30,
    GENERIC_READ = 31
    }

    public enum CreationDisposition : uint
    {
    CREATE_NEW = 1,
    CREATE_ALWAYS = 2,
    OPEN_EXISTING = 3,
    OPEN_ALWAYS = 4,
    TRUNCATE_EXISTING = 5
    }

PInvoke mciSendString

The p/invoke has one error that I can see. The return value should be of type int or uint since MCIERROR is a 32 bit integer. In C# long is 64 bits wide.

Beyond that, the way you are calling mciSendString is fine. In fact, your code plays an mp3 file just fine when I run it, even with the erroneous return type declaration.

So, why does it fail for you? The most obvious reason is that the multimedia functions rely on the presence of a message loop. Perhaps the thread which calls this code does not service a message queue. Are you making the call from a console application for instance?

If the thread does have a message queue, and pumps it properly, then I'm not sure what else to suggest. The next step would be to perform some error checking which you do not do at the moment. Take note of the values returned by mciSendString and see if they indicate errors.


You've now discovered that mciSendString is returning error code MCIERR_INTERNAL. To me that sounds like your problem is environmental. Your code works perfectly well for me so it seems that there is a problem with your audio setup/drivers or a problem with the .mp3 file. But there's nothing more that we can do to help you with your code since the problem is not in your code.



Related Topics



Leave a reply



Submit