Есть такая WIN API функция:
DWORD GetNamedSecurityInfo(
LPTSTR pObjectName,
SE_OBJECT_TYPE ObjectType,
SECURITY_INFORMATION SecurityInfo,
PSID* ppsidOwner,
PSID* ppsidGroup,
PACL* ppDacl,
PACL* ppSacl,
PSECURITY_DESCRIPTOR* ppSecurityDescriptor
);
В числе прочих она принимает 4 опциаональных указателя на указатель: ppsidOwner, ppsidGroup, ppDacl и ppSacl. Какждый из этих параметров может принимать NULL — это охначает, что данные тебе не нужны.
Возникла необходимость вызвать эту функцию из C# и встал вопрос, как же её корректно объявить.
Решение в лоб не работает:
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern uint
GetNamedSecurityInfo(
string pObjectName,
SE_OBJECT_TYPE objectType,
SECURITY_INFORMATION securityInfo,
ref IntPtr pSidOwner,
ref IntPtr pSidGroup,
ref IntPtr pDacl,
ref IntPtr pSacl,
ref IntPtr pSecurityDescriptor);
ибо в этом случае передать null или IntPtr.Zero в опциональные параметры не получится.
Поэтому немного подумав нашёл 2-а альтернативных решения, первое сложно в сипользовании, но имеет адекватную декларацию самой функции. Второе просто использовать, но декларация функции мягко говоря не очевидна. Душой склоняюсь ко второму, но боюсь, что есть какой-то подвох, поэтому прошу совета, кто что может сказать.
Итак, решение первое — ручное получение указателя на указатель с помощью AllocHGlobal / StructureToPtr
// декларация
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern uint
GetNamedSecurityInfo(
string pObjectName,
SE_OBJECT_TYPE objectType,
SECURITY_INFORMATION securityInfo,
IntPtr pSidOwner,
IntPtr pSidGroup,
IntPtr pDacl,
IntPtr pSacl,
ref IntPtr pSecurityDescriptor);
//...
// использование:
// сделали pointer-to-pointer вручную
IntPtr ppSid = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
Marshal.StructureToPtr(IntPtr.Zero, ppSid, false);
// вызвали (NULL в данном случае - это IntPtr.Zero)
uint result = NativeMethods.GetNamedSecurityInfo(name,
NativeMethods.SE_OBJECT_TYPE.SE_FILE_OBJECT,
NativeMethods.SECURITY_INFORMATION.Owner,
ppSid, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref sd);
// "разыменовали" результат
IntPtr pSid = (System.IntPtr)Marshal.PtrToStructure(ppSid, typeof(IntPtr));
// не забыли почистить за собой
Marshal.FreeHGlobal(ppSid);
Решение второе: используем тот факт, что указатель-на-указатель — это есть массив указателей из одного элемента:
// декларация
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern uint
GetNamedSecurityInfo(
string pObjectName,
SE_OBJECT_TYPE objectType,
SECURITY_INFORMATION securityInfo,
[MarshalAs(UnmanagedType.LPArray, SizeConst = 1)]
IntPtr[] pSidOwner,
[MarshalAs(UnmanagedType.LPArray, SizeConst = 1)]
IntPtr[] pSidGroup,
[MarshalAs(UnmanagedType.LPArray, SizeConst = 1)]
IntPtr[] pDacl,
[MarshalAs(UnmanagedType.LPArray, SizeConst = 1)]
IntPtr[] pSacl,
ref IntPtr pSecurityDescriptor);
// ...
// использование
// сделали "pointer-to-pointer"
IntPtr[] ppSid = new IntPtr[1];
ppSid[0] = IntPtr.Zero;
// вызвали (NULL в данном случае - это null :) )
uint result = NativeMethods.GetNamedSecurityInfo(name,
NativeMethods.SE_OBJECT_TYPE.SE_FILE_OBJECT,
NativeMethods.SECURITY_INFORMATION.Owner,
ppSid, null, null, null, ref sd);
// "разыменовали"
IntPtr pSid = ppSid[0];
// всё
Преимущества второго варианта очевидны, все операции по выделению памяти, копированию (если они есть) остаются на совести среди. Вот только чиста ли эта совесть? Нет ли здесь каких-то сркытых утечек или проблем, уже больно подозрительным решение кажется
![](/Forum/Images/smile.gif)
. Что скажет многоуважаемый ALL?
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.