New functions lmemcpynAtoW and lmemcpynWtoA for converting
REG_MULTI_SZ (including \0x00)
Better debug output for REG_BINARY and REG_MULTI_SZ
Rewritten RegQueryValueEx32[A|W]
diff --git a/misc/registry.c b/misc/registry.c
index e8f22e2..641b280 100644
--- a/misc/registry.c
+++ b/misc/registry.c
@@ -147,6 +147,70 @@
dest[nchars] = 0;
return dest;
}
+/*
+ * we need to convert A to W with '\0' in strings (MULTI_SZ)
+ */
+
+static LPWSTR lmemcpynAtoW( LPWSTR dst, LPCSTR src, INT32 n )
+{ LPWSTR p = dst;
+
+ TRACE(reg,"\"%s\" %i\n",src, n);
+
+ while (n-- > 0) *p++ = (WCHAR)(unsigned char)*src++;
+
+ return dst;
+}
+static LPSTR lmemcpynWtoA( LPSTR dst, LPCWSTR src, INT32 n )
+{ LPSTR p = dst;
+
+ TRACE(string,"L\"%s\" %i\n",debugstr_w(src), n);
+
+ while (n-- > 0) *p++ = (CHAR)*src++;
+
+ return dst;
+}
+
+static void debug_print_value (LPBYTE lpbData, DWORD type, DWORD len)
+{ if (lpbData)
+ { switch(type)
+ { case REG_SZ:
+ TRACE(reg," Data(sz)=%s\n",debugstr_w((LPCWSTR)lpbData));
+ break;
+
+ case REG_DWORD:
+ TRACE(reg," Data(dword)=0x%08lx\n",(DWORD)*lpbData);
+ break;
+
+ case REG_MULTI_SZ:
+ { int i;
+ LPCWSTR ptr = (LPCWSTR)lpbData;
+ for (i=0;ptr[0];i++)
+ { TRACE(reg, " MULTI_SZ(%i=%s)\n", i, debugstr_w(ptr));
+ ptr += lstrlen32W(ptr)+1;
+ }
+ }
+ break;
+
+ case REG_BINARY:
+ { char szTemp[100]; /* 3*32 + 3 + 1 */
+ int i;
+ for ( i = 0; i < len ; i++)
+ { sprintf (&(szTemp[i*3]),"%02x ", lpbData[i]);
+ if (i>=31)
+ { sprintf (&(szTemp[i*3+3]),"...");
+ break;
+ }
+ }
+ TRACE(reg," Data(raw)=(%s)\n", szTemp);
+ }
+ break;
+
+ default:
+ FIXME(reg, " Unknown data type %ld\n", type);
+ } /* switch */
+ } /* if */
+}
+
/******************************************************************************
@@ -2122,6 +2186,7 @@
* RETURNS
* ERROR_SUCCESS: Success
* ERROR_MORE_DATA: The specified buffer is not big enough to hold the data
+ * !!! buffer is untouched. The MS-documentation is wrong !!!
*/
DWORD WINAPI RegQueryValueEx32W( HKEY hkey, LPWSTR lpValueName,
LPDWORD lpdwReserved, LPDWORD lpdwType,
@@ -2129,100 +2194,84 @@
{
LPKEYSTRUCT lpkey;
int i;
+ DWORD ret;
- TRACE(reg,"(0x%x,%s,%p,%p,%p,%ld)\n", hkey, debugstr_w(lpValueName),
- lpdwReserved, lpdwType, lpbData, lpcbData?*lpcbData:0);
+ TRACE(reg,"(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
+ lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
- lpkey = lookup_hkey(hkey);
- if (!lpkey)
- return ERROR_INVALID_HANDLE;
+ lpkey = lookup_hkey(hkey);
- /* Reserved must be NULL (at least for now) */
- if (lpdwReserved)
- return ERROR_INVALID_PARAMETER;
+ if (!lpkey)
+ return ERROR_INVALID_HANDLE;
- /* An empty name string is equivalent to NULL */
- if (lpValueName && !*lpValueName)
- lpValueName = NULL;
+ if ((lpbData && ! lpcbData) || lpdwReserved)
+ return ERROR_INVALID_PARAMETER;
- if (lpValueName==NULL) {
- /* Use key's unnamed or default value, if any */
- for (i=0;i<lpkey->nrofvalues;i++)
- if (lpkey->values[i].name==NULL)
- break;
- } else {
- /* Search for the key name */
- for (i=0;i<lpkey->nrofvalues;i++)
- if ( lpkey->values[i].name &&
- !lstrcmpi32W(lpValueName,lpkey->values[i].name)
- )
- break;
+ /* An empty name string is equivalent to NULL */
+ if (lpValueName && !*lpValueName)
+ lpValueName = NULL;
+
+ if (lpValueName==NULL)
+ { /* Use key's unnamed or default value, if any */
+ for (i=0;i<lpkey->nrofvalues;i++)
+ if (lpkey->values[i].name==NULL)
+ break;
+ }
+ else
+ { /* Search for the key name */
+ for (i=0;i<lpkey->nrofvalues;i++)
+ if ( lpkey->values[i].name && !lstrcmpi32W(lpValueName,lpkey->values[i].name))
+ break;
}
- if (i==lpkey->nrofvalues) {
- TRACE(reg,"Key not found\n");
- if (lpValueName==NULL) {
- /* Empty keyname not found */
- if (lpbData) {
- *(WCHAR*)lpbData = 0;
- *lpcbData = 2;
- }
- if (lpdwType)
- *lpdwType = REG_SZ;
- TRACE(reg, "Returning an empty string\n");
- return ERROR_SUCCESS;
- }
- return ERROR_FILE_NOT_FOUND;
+ if (i==lpkey->nrofvalues)
+ { TRACE(reg," Key not found\n");
+ if (lpValueName==NULL)
+ { /* Empty keyname not found */
+ if (lpbData)
+ { *(WCHAR*)lpbData = 0;
+ *lpcbData = 2;
+ }
+ if (lpdwType)
+ *lpdwType = REG_SZ;
+ TRACE(reg, " Returning an empty string\n");
+ return ERROR_SUCCESS;
+ }
+ return ERROR_FILE_NOT_FOUND;
}
- if (lpdwType)
- *lpdwType = lpkey->values[i].type;
+ ret = ERROR_SUCCESS;
- if (lpbData==NULL) {
- /* Data is not required */
- if (lpcbData==NULL) {
- /* And data size is not required */
- /* So all that is returned is the type (set above) */
- return ERROR_SUCCESS;
- }
- /* Set the size required and return success */
- *lpcbData = lpkey->values[i].len;
- return ERROR_SUCCESS;
- }
+ if (lpdwType) /* type required ?*/
+ *lpdwType = lpkey->values[i].type;
- if (*lpcbData<lpkey->values[i].len) {
- /* The size was specified, but the data is too big for it */
- /* Instead of setting it to NULL, fill in with as much as possible */
- /* But the docs do not specify how to handle the lpbData here */
- /* *(WCHAR*)lpbData= 0; */
- memcpy(lpbData,lpkey->values[i].data,*lpcbData);
- *lpcbData = lpkey->values[i].len;
- return ERROR_MORE_DATA;
- }
+ if (lpcbData) /* size required ?*/
+ { if (lpbData) /* data required ?*/
+ { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
+ memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
+ else
+ ret = ERROR_MORE_DATA;
+ }
+ *lpcbData = lpkey->values[i].len;
- memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
+ /* fixme: hack to fake return value for REG_MULTI_SZ */
+ if(lpkey->values[i].type==REG_MULTI_SZ)
+ { FIXME(reg,"fake empty return value for REG_MULTI_SZ\n");
+ *lpcbData = 4;
+ if (lpbData)
+ { lpbData[0] = 0x00;
+ lpbData[1] = 0x00;
+ lpbData[2] = 0x00;
+ lpbData[3] = 0x00;
+ }
+ }
+ }
- /* Extra debugging output */
- if (lpdwType) {
- switch(*lpdwType){
- case REG_SZ:
- TRACE(reg," Data(sz)=%s\n",debugstr_w((LPCWSTR)lpbData));
- break;
- case REG_DWORD:
- TRACE(reg," Data(dword)=%lx\n", (DWORD)*lpbData);
- break;
- case REG_BINARY:
- TRACE(reg," Data(binary)\n");
- /* Is there a way of printing this in readable form? */
- break;
- default:
- TRACE(reg, "Unknown data type %ld\n", *lpdwType);
- } /* switch */
- } /* if */
+ debug_print_value ( lpbData, lpkey->values[i].type, lpkey->values[i].len);
- /* Set the actual size */
- *lpcbData = lpkey->values[i].len;
- return ERROR_SUCCESS;
+ TRACE(reg," (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
+
+ return ret;
}
@@ -2259,82 +2308,68 @@
/******************************************************************************
* RegQueryValueEx32A [ADVAPI32.157]
+ *
+ * NOTES:
+ * the documantation is wrong: if the buffer is to small it remains untouched
+ *
+ * FIXME: check returnvalue (len) for an empty key
*/
DWORD WINAPI RegQueryValueEx32A( HKEY hkey, LPSTR lpszValueName,
LPDWORD lpdwReserved, LPDWORD lpdwType,
LPBYTE lpbData, LPDWORD lpcbData )
{
LPWSTR lpszValueNameW;
- LPBYTE buf;
- DWORD ret,myxlen;
- DWORD *mylen;
- DWORD type;
+ LPBYTE mybuf = NULL;
+ DWORD ret, mytype, mylen = 0;
- TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n", hkey,debugstr_a(lpszValueName),
- lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
+ TRACE(reg,"(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
+ lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
- lpszValueNameW = lpszValueName?strdupA2W(lpszValueName):NULL;
-
- /* Why would this be set? It is just an output */
- if (lpdwType)
- type = *lpdwType;
-
- if (lpbData) {
- myxlen = 0;
- mylen = &myxlen;
- buf = xmalloc(4);
- /* Only get the size for now */
- ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved,
- &type, buf, mylen );
- free(buf);
- if (ret==ERROR_MORE_DATA) {
- buf = (LPBYTE)xmalloc(*mylen);
- } else {
- buf = (LPBYTE)xmalloc(2*(*lpcbData));
- myxlen = 2*(*lpcbData);
- }
- } else {
- /* Data is not required */
- buf=NULL;
- if (lpcbData) {
- myxlen = *lpcbData*2;
- mylen = &myxlen;
- } else
- mylen = NULL;
+ if (!lpcbData && lpbData) /* buffer without size is illegal */
+ { return ERROR_INVALID_PARAMETER;
}
- /* Now get the data */
- ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, &type,
- buf, mylen );
- if (lpdwType)
- *lpdwType=type;
+ lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
+
+ /* get just the type first */
+ ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
+
+ if ( ret != ERROR_SUCCESS ) /* failed ?? */
+ { if(lpszValueNameW) free(lpszValueNameW);
+ return ret;
+ }
+
+ if (lpcbData) /* at least length requested? */
+ { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
+ { if (lpbData) /* value requested? */
+ { mylen = 2*( *lpcbData );
+ mybuf = (LPBYTE)xmalloc( mylen );
+ }
- if (ret==ERROR_SUCCESS) {
- if (buf) {
- if (UNICONVMASK & (1<<(type))) {
- /* convert UNICODE to ASCII */
- lstrcpyWtoA(lpbData,(LPWSTR)buf);
- *lpcbData = myxlen/2;
- } else {
- if (myxlen>*lpcbData)
- ret = ERROR_MORE_DATA;
- else
- memcpy(lpbData,buf,myxlen);
+ ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
- *lpcbData = myxlen;
- }
- } else {
- if ((UNICONVMASK & (1<<(type))) && lpcbData)
- *lpcbData = myxlen/2;
- }
- } else {
- if ((UNICONVMASK & (1<<(type))) && lpcbData)
- *lpcbData = myxlen/2;
+ if (ret == ERROR_SUCCESS )
+ { if ( lpbData )
+ { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
+ }
+ }
+
+ *lpcbData = mylen/2; /* size is in byte! */
+ }
+ else /* no strings, call it straight */
+ { ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
+ }
+ }
+
+ if (lpdwType) /* type when requested */
+ { *lpdwType = mytype;
}
- if(buf) free(buf);
- if(lpszValueNameW) free(lpszValueNameW);
- return ret;
+ TRACE(reg," (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
+
+ if(mybuf) free(mybuf);
+ if(lpszValueNameW) free(lpszValueNameW);
+ return ret;
}
@@ -2432,29 +2467,18 @@
DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
DWORD cbData)
{
- LPKEYSTRUCT lpkey;
- int i;
+ LPKEYSTRUCT lpkey;
+ int i;
- TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
+ TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
dwReserved, dwType, lpbData, cbData);
- switch (dwType) {
- case REG_SZ:
- TRACE(reg," Data(sz)=%s\n", debugstr_w((LPCWSTR)lpbData));
- break;
- case REG_BINARY:
- TRACE(reg," Data(binary)\n");
- break;
- case REG_DWORD:
- TRACE(reg," Data(dword)=%lx\n", (DWORD)lpbData);
- break;
- default:
- TRACE(reg,"Unknown type: %ld\n", dwType);
- }
+ debug_print_value ( lpbData, dwType, cbData );
- lpkey = lookup_hkey( hkey );
- if (!lpkey)
- return ERROR_INVALID_HANDLE;
+ lpkey = lookup_hkey( hkey );
+
+ if (!lpkey)
+ return ERROR_INVALID_HANDLE;
lpkey->flags |= REG_OPTION_TAINTED;
@@ -2507,23 +2531,33 @@
LPWSTR lpszValueNameW;
DWORD ret;
- TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
+ if (!lpbData)
+ return (ERROR_INVALID_PARAMETER);
+
+ TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
dwReserved,dwType,lpbData,cbData);
- if ((1<<dwType) & UNICONVMASK) {
- buf=(LPBYTE)strdupA2W(lpbData);
- cbData=2*strlen(lpbData)+2;
- } else
- buf=lpbData;
- if (lpszValueName)
- lpszValueNameW = strdupA2W(lpszValueName);
+ if ((1<<dwType) & UNICONVMASK)
+ { buf = (LPBYTE)xmalloc( cbData *2 );
+ lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
+ cbData=2*cbData;
+ }
else
- lpszValueNameW = NULL;
+ buf=lpbData;
+
+ if (lpszValueName)
+ lpszValueNameW = strdupA2W(lpszValueName);
+ else
+ lpszValueNameW = NULL;
+
ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
+
if (lpszValueNameW)
- free(lpszValueNameW);
+ free(lpszValueNameW);
+
if (buf!=lpbData)
- free(buf);
+ free(buf);
+
return ret;
}