Interop Woes

C

Chris B.

If anyone can figure out how to implement the following C++ function in C#
using interop, I'd be very appreciative.

I have not been successful in getting it to work correctly using interop
(without using unsafe code) because of the pointer issues of the structure.

Thanks,
Chris

//------------------------------------------------------------

HANDLE __stdcall CreateAllAccessMutex(BOOL bInitialOwner, const wchar_t
*pszName)
{
HANDLE rc = NULL;
SECURITY_DESCRIPTOR sd;
SECURITY_ATTRIBUTES sa;

// A security descriptor with a NULL DACL must be used because this
function can be initially called
// by an application running as a service which will create the mutex with
a default security
// descriptor that does not allow user-mode applications to open the mutex
by name with CreateMutex.

if (InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) //
initialize the security descriptor
{
if (SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE)) // add a NULL
DACL to the security descriptor
{
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;

rc = CreateMutexW(&sa, bInitialOwner, pszName);
}
}

return rc;
}
 
W

Willy Denoyette [MVP]

Better would be to derive from WaitHandle but following class could give you
a head start :

[StructLayout(LayoutKind.Sequential)]
internal struct SECURITY_DESCRIPTOR
{
public byte Revision;
public byte Sbz1;
public ushort Control;
public uint Owner;
public uint Group;
public uint Sacl;
public uint Dacl;
}

[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
internal int nLength;
internal IntPtr pSecurityDescriptor;
internal bool bInheritHandle;
}

class Win32NamedMutex : IDisposable
{
[DllImport("kernel32", SetLastError=true),
SuppressUnmanagedCodeSecurityAttribute]
static extern IntPtr CreateMutex(
ref SECURITY_ATTRIBUTES pSecurityAttributes, // pointer to sa
bool bInitialOwner,
string lpName
);
[DllImport("kernel32", SetLastError=true),
SuppressUnmanagedCodeSecurityAttribute]
static extern bool ReleaseMutex(
IntPtr handle
);

[DllImport("advapi32", SetLastError=true),
SuppressUnmanagedCodeSecurityAttribute]
static extern bool InitializeSecurityDescriptor(
IntPtr pSecurityDescriptor, // pointer to sd
int dwRevision // revision must be SECURITY_DESCRIPTOR_REVISION (1)
);
[DllImport("advapi32", SetLastError=true),
SuppressUnmanagedCodeSecurityAttribute]
static extern bool SetSecurityDescriptorDacl(
IntPtr pSecurityDescriptor, // pointer to sd
bool bDaclPresent,
IntPtr pDacl,
bool bDaclDefaulted
);
[DllImport("advapi32", SetLastError=true),
SuppressUnmanagedCodeSecurityAttribute]
static extern bool IsValidSecurityDescriptor(IntPtr pSecurityDescriptor);
// pointer to sd
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
IntPtr pSd;
IntPtr handle;
private bool disposed = false;

public IntPtr CreateNamedMutex(string name, ref bool initialOwner)
{
handle = IntPtr.Zero;
if (CreateSaWithNullDaclSd())
{
handle = CreateMutex(ref sa, initialOwner, name);
if (handle == IntPtr.Zero)
{
Console.WriteLine("{0}", Marshal.GetLastWin32Error());
}
else {
if(Marshal.GetLastWin32Error() == 183) //ERROR_ALREADY_EXISTS
initialOwner = false;
}
}
return handle;
}
private bool CreateSdWithNullDacl()
{
bool ret = false;
sd = new SECURITY_DESCRIPTOR();
pSd = Marshal.AllocHGlobal( Marshal.SizeOf(sd) );
Marshal.StructureToPtr(sd, pSd, true);
// Initialize SD with revision level 1 (mandatory)
if(InitializeSecurityDescriptor(pSd, 1))
{
// set NULL DACL in SD, this sets "everyone" access privileges
if (SetSecurityDescriptorDacl(pSd, true, IntPtr.Zero, true))
{
ret = IsValidSecurityDescriptor(pSd); // set ret = true if valid SD
}
else {ret = false;}
}
return ret;
}
private bool CreateSaWithNullDaclSd()
{
if (CreateSdWithNullDacl())
{
sa = new SECURITY_ATTRIBUTES();
sa.pSecurityDescriptor = pSd;
sa.bInheritHandle = false;
sa.nLength = Marshal.SizeOf(sa);
return true;
}
return false;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if(!this.disposed)
{
// Release unmanaged Mutex.
ReleaseMutex(this.handle);
handle = IntPtr.Zero;
}
disposed = true;
}
~Win32NamedMutex()
{
Dispose(false);
// BUG BUG, finalizer should never be called. Object should be Disposed
by client.
// Failed to call dispose, will throw in debug build
#if DEBUG
throw new Exception("Finalizer called on disposable object");
#endif
}
}

Use case:

IntPtr handle;
bool owner = true;
using(Win32NamedMutex ws = new Win32NamedMutex())
{
handle = ws.CreateNamedMutex("Global\\myMutex", ref owner);
if (owner != true)
{
// already owned wait until handle signaled
AutoResetEvent wh = new AutoResetEvent(false);
wh.Handle = handle;
wh.WaitOne();
}
else
{
.....// Do some work while owning Mutex

}
} // release mutex resources
.....


Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top