1、问,昨天你从Nsis 的ReadRegStr 发现windows api的小细节是什么?

1、问,昨天你从Nsis 的ReadRegStr 发现windows api的小细节是什么?

问,昨天你从Nsis 的ReadRegStr 发现windows api的小细节是什么?

简述:因为新的需求,需要安装程序读出软件主程序写入注册表的值,因此使用Nsis的ReadRegStr读取注册表中REG_SZ类型的值。

步骤:

1、(公司前辈的代码)(定义了宏UNICODE)

if (RegOpenKeyEx(HKEY_CURRENT_USER,TEXT("Software\\MyApp"),0,KEY_READ | KEY_WRITE,&hKey) != ERROR_SUCCESS)

return -1;

if (RegSetValueEx(hKey,TEXT("SomeData"),0,REG_SZ,(LPCBYTE)"1",1) == ERROR_SUCCESS)

{

Sleep(500);

RegCloseKey(hKey);

return 0;

}

此处UNICODE字符集起到了关键的作用。

由于是UNICODE,LPCBYTE的字符串存入注册表就成了1个字节。

应该这样,RegSetValueExW 在存入RES_SZ的字符串时,也应该保证最后两个成员是宽字符的(即UNICODE)。

2、nsis代码

ReadRegDWORD $reg_value HKCU "Software\MyApp" "SomeData"

然而,$reg_value 总是空的。

查阅了文档:

ReadRegStr

user_var(output) root_key sub_key name

Reads from the registry into the user variable $x. Valid values for root_key are listed under WriteRegStr. The error flag will be set and $x will be set to an empty string ("") if the string is not present. If the value is present, but is of type REG_DWORD, it will be read and converted to a string and the error flag will be set.

ReadRegStr $0 HKLM Software\NSIS ""

DetailPrint "NSIS is installed at: $0"

以及看了ReadRegDWORD的文档,

ReadRegDWORD

user_var(output) root_key sub_key name

Reads a 32 bit DWORD from the registry into the user variable $x. Valid values for root_key are listed under WriteRegStr. The error flag will be set and $x will be set to an empty string ("" which is 0) if the DWORD is not present. If the value is present, but is not a DWORD, it will be read as a string and the error flag will be set.

ReadRegDWORD $0 HKLM Software\NSIS VersionBuild

尝试了各种办法,总是为空。

后来无意间通过注册表编辑器,手动将Software\\MyApp 下的SomeData修改为0 (REG_SZ类型)。结果nsis能读出来了,然后又修改为1 ,也能读取来了。

无语了,只能查看写的代码。就看到了上面的代码。

RegSetValueEx(hKey,TEXT("SomeData"),0,REG_SZ,(LPCBYTE)"1",1)

注意红色部分。

仅仅写入了字符串的第一个字节。也就是字符串“1”的后面的"\0" 没有写入注册表。然而注册表编辑器能自动适应这种数据,可以展现出对应的字符串 0 或 1 。虽然数据实际是没有结尾的"\0"。

解决办法:简单的将写入的字节数修改为2 即可。

RegSetValueEx(hKey,TEXT("SomeData"),0,REG_SZ,(LPCBYTE)"1",2)

3、继续探索写入代码:

其实RegSetValueEx的文档写的很明白,只是前辈的代码没考虑。

RegSetValueEx Function

cbData

The size of the information pointed to by the lpData parameter, in bytes. If the data is of type REG_SZ, REG_EXPAND_SZ, or REG_MULTI_SZ, cbData must include the size of the terminating null character or characters.

4、继续探索nsis的代码:

查看nsis的代码,找到ReadRegStr和ReadRegDWORD的实现。

 case EW_READREGSTR: // read registry string

      {

        HKEY hKey=myRegOpenKey(KEY_READ);

        char *p=var0;

        char *buf3=GetStringFromParm(0x33); // buf3 == key name

        p[0]=0;

        if (hKey)

        {

          DWORD l = NSIS_MAX_STRLEN - 1;

          DWORD t;

          if (RegQueryValueEx(hKey,buf3,NULL,&t,p,&l) != ERROR_SUCCESS ||

              (t != REG_DWORD && t != REG_SZ && t != REG_EXPAND_SZ))

          {

            p[0]=0;

            exec_error++;

          }

          else

          {

            if (t==REG_DWORD)

            {

              exec_error += !parm4;

              myitoa(p,*((DWORD*)p));

            }

            else

            {

              exec_error += parm4;

              p[l]=0;

            }

          }

          RegCloseKey(hKey);

        }

        else exec_error++;

     }

关键就在红色这行。

另外最关键的是nsis的编译,采用的多字节字符集

由于存入是UNICODE存入了LPBYTE的数据,而读取采用多字节方式读取,导致读出的l(字母L的小写)为0 。

----------------------------------------

5、验证一个问题:

UNICODE 下执行以下代码:

HKEY hKey;

if (RegOpenKeyEx(HKEY_CURRENT_USER,TEXT("SOFTWARE\\MyApp"),0,KEY_READ | KEY_WRITE,&hKey) != ERROR_SUCCESS)

{

cout <<1 <<endl;

return -1;

}

if (RegSetValueEx(hKey,TEXT("SomeData"),0,REG_SZ,(LPCBYTE)"1",1) == ERROR_SUCCESS)

{

RegCloseKey(hKey);

}

else

{

RegCloseKey(hKey);

}

多字节下通过以下代码,读出的长度是0 。

DWORD l = 20 - 1;

          DWORD t;

unsigned char * p = new unsigned char[20];

p[0] = 0;

HKEY hKey;

int exec_error;

 if (RegOpenKeyEx(HKEY_CURRENT_USER,TEXT("SOFTWARE\\MyApp"),0,KEY_READ | KEY_WRITE,&hKey) != ERROR_SUCCESS)

 {

cout << 3<<endl;

return -1;

}

          if (RegQueryValueEx(hKey,TEXT("SomeData"),NULL,&t,p,&l) != ERROR_SUCCESS ||

              (t != REG_DWORD && t != REG_SZ && t != REG_EXPAND_SZ))

          {

            p[0]=0;

            exec_error++;

cout << "err"<<endl;

          }

          else

          {

            if (t==REG_DWORD)

            {

              //exec_error += !parm4;

              //myitoa(p,*((DWORD*)p));

  

  cout << 4<<endl;

            }

            else

            {

              //exec_error += parm4;

              p[l]=0;

  cout <<"result "<<endl;

  cout << l <<endl; // 这里输出0.

  cout << p <<endl;// 这里就为空。也就是nsis读取不到数据的原因。虽然成功,但是数据为空。

  

            }

}

从而可见,注册表编辑器也是UNICODE方式。

环境:win7 sp1.

你可能感兴趣的:(1、问,昨天你从Nsis 的ReadRegStr 发现windows api的小细节是什么?)