5

我正在尝试移植以下 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# 程序以管理员权限和本地系统帐户运行。我需要.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);
4

3 回答 3

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++ 代码。

于 2013-06-05T08:43:29.430 回答
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);

您没有将它们声明为输出参数,并且在RegQueryInfoKeyWin32 调用中它们是 _Out_opt_。

于 2013-06-04T23:12:38.990 回答
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

于 2013-06-05T03:14:27.743 回答