C # P / Invoke Win32 RegQueryInfoKey Function

I am trying to port the following code in C ++:

BOOL SyskeyGetClassBytes(HKEY hKeyReg,LPSTR keyName,LPSTR valueName,LPBYTE classBytes) { HKEY hKey,hSubKey; DWORD dwDisposition=0,classSize; BYTE classStr[16]; LONG ret; BOOL isSuccess = FALSE; ret = RegCreateKeyEx(hKeyReg,keyName,0,NULL,REG_OPTION_NON_VOLATILE,KEY_QUERY_VALUE,NULL,&hKey,&dwDisposition); if(ret!=ERROR_SUCCESS) return FALSE; else if(dwDisposition!=REG_OPENED_EXISTING_KEY) { RegCloseKey(hKey); return FALSE; } else { if(RegOpenKeyEx(hKey,valueName,0,KEY_READ,&hSubKey)==ERROR_SUCCESS) { classSize = 8+1; ret = RegQueryInfoKey(hSubKey,(LPTSTR)classStr,&classSize,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); if((ret==ERROR_SUCCESS)&&(classSize==8)) { classBytes[0]= (HexDigitToByte(classStr[0]) << 4) | HexDigitToByte(classStr[1]); classBytes[1]= (HexDigitToByte(classStr[2]) << 4) | HexDigitToByte(classStr[3]); classBytes[2]= (HexDigitToByte(classStr[4]) << 4) | HexDigitToByte(classStr[5]); classBytes[3]= (HexDigitToByte(classStr[6]) << 4) | HexDigitToByte(classStr[7]); isSuccess = TRUE; } RegCloseKey(hSubKey); } RegCloseKey(hKey); } return isSuccess; 

}

I spent like 5 hours trying to figure out my problem, without success. I know that I correctly call this method. My c # code

  unsafe static bool SyskeyGetClassBytes(RegistryHive hKeyReg, string keyName, string valueName, byte* classBytes) { UIntPtr hSubKey; UIntPtr hKey; RegResult tmp; ; uint classSize; StringBuilder classStr = new StringBuilder(); int ret; bool isSuccess = false; ret = RegCreateKeyEx(hKeyReg, keyName, 0, null, RegOption.NonVolatile, RegSAM.QueryValue, UIntPtr.Zero, out hKey, out tmp); if (ret != 0) { return false; } else if (tmp != RegResult.OpenedExistingKey) { return false; } else { int res = RegOpenKeyEx(hKey, valueName, 0, (int)RegSAM.Read, out hSubKey); if (res == 0) { classSize = 8 + 1; ret = RegQueryInfoKey(hSubKey, out classStr, ref classSize, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if ((classSize == 8)) { classBytes[0] = (byte)((byte)(HexDigitToByte(classStr[0]) << (byte)4) | HexDigitToByte(classStr[1])); classBytes[1] = (byte)((byte)(HexDigitToByte(classStr[2]) << (byte)4) | HexDigitToByte(classStr[3])); classBytes[2] = (byte)((byte)(HexDigitToByte(classStr[4]) << (byte)4) | HexDigitToByte(classStr[5])); classBytes[3] = (byte)((byte)(HexDigitToByte(classStr[6]) << (byte)4) | HexDigitToByte(classStr[7])); isSuccess = true; } RegCloseKey(hSubKey); } else { return false; } RegCloseKey(hKey); } return isSuccess; } 

It’s a little difficult for me to debug, but in the end I decided that the problem was arising on this line. Execution seems to stop afterwards.

  ret = RegQueryInfoKey(hSubKey, out classStr, ref classSize, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); 

I know that this is not a permissions problem, since this C # program works with admin perms and as a local system account. The method I need to prevent .Net APIs from offering is RegQueryInfoKey. Signatures used and P / Invoke types:

  [StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES { public int nLength; public unsafe byte* lpSecurityDescriptor; public int bInheritHandle; } [Flags] public enum RegOption { NonVolatile = 0x0, Volatile = 0x1, CreateLink = 0x2, BackupRestore = 0x4, OpenLink = 0x8 } [Flags] public enum RegSAM { QueryValue = 0x0001, SetValue = 0x0002, CreateSubKey = 0x0004, EnumerateSubKeys = 0x0008, Notify = 0x0010, CreateLink = 0x0020, WOW64_32Key = 0x0200, WOW64_64Key = 0x0100, WOW64_Res = 0x0300, Read = 0x00020019, Write = 0x00020006, Execute = 0x00020019, AllAccess = 0x000f003f } public enum RegResult { CreatedNewKey = 0x00000001, OpenedExistingKey = 0x00000002 } [DllImport("advapi32.dll", CharSet = CharSet.Auto)] public static extern int RegOpenKeyEx( UIntPtr hKey, string subKey, int ulOptions, int samDesired, out UIntPtr hkResult); [DllImport("advapi32.dll", SetLastError = true)] public static extern int RegCloseKey( UIntPtr hKey); [DllImport("advapi32.dll", SetLastError = true)] static extern int RegCreateKeyEx( RegistryHive hKey, string lpSubKey, int Reserved, string lpClass, RegOption dwOptions, RegSAM samDesired, UIntPtr lpSecurityAttributes, out UIntPtr phkResult, out RegResult lpdwDisposition); [DllImport("advapi32.dll", EntryPoint = "RegQueryInfoKey", CallingConvention = CallingConvention.Winapi, SetLastError = true)] extern private static int RegQueryInfoKey( UIntPtr hkey, out StringBuilder lpClass, ref uint lpcbClass, IntPtr lpReserved, IntPtr lpcSubKeys, IntPtr lpcbMaxSubKeyLen, IntPtr lpcbMaxClassLen, IntPtr lpcValues, IntPtr lpcbMaxValueNameLen, IntPtr lpcbMaxValueLen, IntPtr lpcbSecurityDescriptor, IntPtr lpftLastWriteTime); 
+4
source share
3 answers

The lpClass parameter is declared incorrectly. Pass StringBuilder by value.

 [DllImport("advapi32.dll")] extern private static int RegQueryInfoKey( UIntPtr hkey, StringBuilder lpClass, ref uint lpcbClass, IntPtr lpReserved, IntPtr lpcSubKeys, IntPtr lpcbMaxSubKeyLen, IntPtr lpcbMaxClassLen, IntPtr lpcValues, IntPtr lpcbMaxValueNameLen, IntPtr lpcbMaxValueLen, IntPtr lpcbSecurityDescriptor, IntPtr lpftLastWriteTime ); 

You also need to allocate an instance of StringBuilder in order to have the desired capacity. So, highlight StringBuilder as follows:

 StringBuilder classStr = new StringBuilder(255);//or whatever length you like 

And then set classSize as follows:

 classSize = classStr.Capacity+1; 

I deleted the parameters before DllImport . Most of them are not necessary, and SetLastError is incorrect.

There may be other problems with your code, but with these changes, at least calling RegQueryInfoKey will match your C ++ code.

+3
source

Try this signature for RegQueryInfoKey :

 [DllImport("advapi32.dll", EntryPoint="RegQueryInfoKey", CallingConvention=CallingConvention.Winapi, SetLastError=true)] extern private static int RegQueryInfoKey( UIntPtr hkey, out StringBuilder lpClass, ref uint lpcbClass, IntPtr lpReserved, out uint lpcSubKeys, out uint lpcbMaxSubKeyLen, out uint lpcbMaxClassLen, out uint lpcValues, out uint lpcbMaxValueNameLen, out uint lpcbMaxValueLen, out uint lpcbSecurityDescriptor, IntPtr lpftLastWriteTime); 

You do not declare them as source parameters, but in the RegQueryInfoKey Win32 call they are _Out_opt_.

0
source

You need to initialize a StringBuilder with enough capacity to hold the number of characters of classSize .

 classSize = 8 + 1; classStr.Capacity = classSize; ret = RegQueryInfoKey(hSubKey, out classStr, ref classSize, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); 

The marshaller will use the capacity set to StringBuilder to send the capacity size buffer to the RegQueryInfoKey function. Without this, you are probably spoiled by memory.

See http://msdn.microsoft.com/en-us/library/s9ts558h.aspx#cpcondefaultmarshalingforstringsanchor3

0
source

Source: https://habr.com/ru/post/1484525/


All Articles