JNI
在开发的项目需要操作到Windows注册表,就想起《java 核心技术》(第11版)里面有个jni示例。抄!
跑一下示例,结果跑不起来,会在java层收到一个自定义的异常,异常信息是“Open key failed”。
原因是,测试代码在setValue,打开一个空的注册表项,需要改一下代码:
老的语句:
if (RegOpenKeyEx(root, cpath, 0, KEY_WRITE, &hkey) != ERROR_SUCCESS)
新的
if (RegCreateKeyExA(root, path.c_str(), 0,nullptr, REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS, nullptr,&hkey,nullptr) != ERROR_SUCCESS)
CPP
java项目,抽象做的很不错。2个类一个Win32RegKey表示一个注册表项,Win32RegKeyNameEnumeration类用来遍历Win32RegKey子项。
C语言的API写一个C的dll本来是一个很好选择,cpp面向对象可以简化dll的操作,继续抄。
Win32RegKey.h
class Win32RegKey {
public:
Win32RegKey(HKEY root, std::string path);
virtual ~Win32RegKey();
std::string getStringValue(const std::string& name) const;
std::int32_t getInt32Value(const std::string& name) const;
BYTE * getValue(_In_ const std::string& name,_Out_ LPDWORD type,_Out_ LPDWORD size) const;
BYTE * getValue(_In_ const std::string& name,_Out_ DWORD type,DWORD size) const;
void setValue(const std::string& name,const std::string& value) const;
void setValue(const std::string& name,const DWORD value) const;
void setValue(_In_ const std::string& name,_In_ BYTE * value,_In_ DWORD size) const;
void setValue(const std::string& name,DWORD type,const BYTE *value,DWORD size) const;
Win32RegEnumeration* names();
private:
Win32RegEnumeration* enumeration = nullptr;
HKEY root;
std::string path;
};
Win32RegEnumeration.h
class Win32RegEnumeration {
public:
Win32RegEnumeration(HKEY root,std::string path);
~Win32RegEnumeration() = default;
std::string nextElement();
bool hasMoreElements();
private:
void startNameEnumeration();
HKEY root;
std::string path;
int index = -1;
HKEY hkey = nullptr;
DWORD maxsize = 0;
DWORD count = 0;
};
具体实现和测试放github
QT
项目是qt的需要移植到qt,qt默认是宽字符的(所以上面JNI的代码API我指定了带A)。
qt的条件编译会自动调用windows带W的API。
我选择适配宽字符,更好地适配QString。
qt版本的头文件版本:
Win32RegKey.h
class Win32RegKey {
public:
Win32RegKey(HKEY root, std::wstring path);
virtual ~Win32RegKey();
std::wstring getWStringValue(const std::wstring& name) const;
std::int32_t getInt32Value(const std::wstring& name) const;
BYTE * getValue(_In_ const std::wstring& name,_Out_ LPDWORD type,_Out_ LPDWORD size) const;
BYTE * getValue(_In_ const std::wstring& name,_Out_ DWORD type,DWORD size) const;
void setValue(const std::wstring& name,const std::wstring& value) const;
void setValue(const std::wstring& name,const DWORD value) const;
void setValue(_In_ const std::wstring& name,_In_ BYTE * value,_In_ DWORD size) const;
void setValue(const std::wstring& name,DWORD type,const BYTE *value,DWORD size) const;
Win32RegEnumeration* names();
private:
Win32RegEnumeration* enumeration = nullptr;
HKEY root;
std::wstring path;
};
Win32RegEnumeration.h
class Win32RegEnumeration {
public:
Win32RegEnumeration(HKEY root,std::wstring path);
~Win32RegEnumeration() = default;
std::wstring nextElement();
bool hasMoreElements();
private:
void startNameEnumeration();
HKEY root;
std::wstring path;
int index = -1;
HKEY hkey = nullptr;
DWORD maxsize = 0;
DWORD count = 0;
};
实现就不贴了,需要注意的是宽字符空间处理的问题(2倍)。
void Win32RegKey::setValue(const std::wstring& name,const std::wstring& value) const {
setValue(name,REG_SZ,reinterpret_cast<const BYTE *>(value.c_str()),(value.size()+1)<<1);
}
读取的时候
case REG_SZ: qDebug() << QString::fromWCharArray((wchar_t*)value3); break;