C# P/Invoke Win32 函数 RegQueryInfoKey

标签 c# winapi registry pinvoke

我正在尝试移植以下 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);

最佳答案

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

关于C# P/Invoke Win32 函数 RegQueryInfoKey,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16928795/

相关文章:

c# - 如何在注册表项中搜索特定值

C#、.NET、注册表项句柄值,如何将它们映射到注册表路径?

c# - 抽象方法还是虚方法?

windows - 以编程方式或从 Windows 中的命令行显示文件属性对话框

c# - XPath 仅返回特定的子节点但与父节点一起返回 - 可能吗?

c++ - 在 Visual Studio C++ 2008 win32 运行时问题中调试与发布构建

c++ - `SetWindowLong()` 函数不执行 't change window style even after calling ` SetWindowPos()`

c++ - WritePrivateProfileStruct 有大小限制吗?

c# - Xpath 选择所有不带 id=x 表的 tr

c# - 当我们使用 new 关键字创建新的 DateTime(对象)时