我正在尝试移植以下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;
}
我花了5个小时试图弄清楚我的问题,但没有成功。我知道我正在调用这种方法。我的C#代码是
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;
}
我有点难以调试,但最终我确定问题是在这一行发生的。之后执行似乎停止了。
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);
我知道这不是权限问题,因为此C#程序使用admin perms AND作为本地系统帐户运行。我需要的.Net API不提供的方法是RegQueryInfoKey。我使用的P / Invoke签名和类型是:
[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);
答案 0 :(得分:3)
lpClass
参数声明不正确。按值传递StringBuilder
。
[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
);
您还需要分配StringBuilder
实例以获得所需的容量。所以,像这样分配StringBuilder
:
StringBuilder classStr = new StringBuilder(255);//or whatever length you like
然后像这样设置classSize
:
classSize = classStr.Capacity+1;
我删除了DllImport
的参数。大多数都没有必要,SetLastError
不正确。
您的代码可能存在其他问题,但是通过这些更改,至少对RegQueryInfoKey
的调用将与您的C ++代码匹配。
答案 1 :(得分:0)
为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);
您没有将它们声明为params,并且在RegQueryInfoKey
Win32调用中它们是_Out_opt_。
答案 2 :(得分:0)
您需要初始化StringBuilder
,并且有足够的容量存储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);
编组将使用StringBuilder
上设置的容量将容量大小的缓冲区发送到RegQueryInfoKey
函数。没有它,你可能已经损坏了记忆。
请参阅http://msdn.microsoft.com/en-us/library/s9ts558h.aspx#cpcondefaultmarshalingforstringsanchor3