| 1899 | |
| 1900 | |
| 1901 | DWORD ReadRegString(HKEY aRootKey, LPTSTR aSubkey, LPTSTR aValueName, LPTSTR aBuf, DWORD aBufSize, DWORD aFlag) |
| 1902 | // Returns the length of the string (0 if empty). |
| 1903 | // Caller must ensure that size of aBuf is REALLY aBufSize (even when it knows aBufSize is more than |
| 1904 | // it needs) because the API apparently reads/writes parts of the buffer beyond the string it writes! |
| 1905 | // Caller must ensure that aBuf isn't NULL because it doesn't seem worth having a "give me the size only" mode. |
| 1906 | // This is because the API might return a size that omits the zero terminator, and the only way to find out for |
| 1907 | // sure is probably to actually fetch the data and check if the terminator is present. |
| 1908 | { |
| 1909 | HKEY hkey; |
| 1910 | if (RegOpenKeyEx(aRootKey, aSubkey, 0, KEY_QUERY_VALUE | aFlag, &hkey) != ERROR_SUCCESS) |
| 1911 | { |
| 1912 | *aBuf = '\0'; |
| 1913 | return 0; |
| 1914 | } |
| 1915 | DWORD buf_size = aBufSize * sizeof(TCHAR); // Caller's value might be a constant memory area, so need a modifiable copy. |
| 1916 | LONG result = RegQueryValueEx(hkey, aValueName, NULL, NULL, (LPBYTE)aBuf, &buf_size); |
| 1917 | RegCloseKey(hkey); |
| 1918 | if (result != ERROR_SUCCESS || !buf_size) // Relies on short-circuit boolean order. |
| 1919 | { |
| 1920 | *aBuf = '\0'; // MSDN says the contents of the buffer is undefined after the call in some cases, so reset it. |
| 1921 | return 0; |
| 1922 | } |
| 1923 | buf_size /= sizeof(TCHAR); // RegQueryValueEx returns size in bytes. |
| 1924 | // Otherwise success and non-empty result. This also means that buf_size is accurate and <= to what we sent in. |
| 1925 | // Fix for v1.0.47: ENSURE PROPER STRING TERMINATION. This is suspected to be a source of crashing. |
| 1926 | // MSDN: "If the data has the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type, the string may not have been |
| 1927 | // stored with the proper null-terminating characters. Therefore, even if the function returns |
| 1928 | // ERROR_SUCCESS, the application should ensure that the string is properly terminated before using |
| 1929 | // it; otherwise, it may overwrite a buffer. (Note that REG_MULTI_SZ strings should have two |
| 1930 | // null-terminating characters.)" |
| 1931 | // MSDN: "If the data has the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type, this size includes any |
| 1932 | // terminating null character or characters." |
| 1933 | --buf_size; // Convert to the index of the last character written. This is safe because above already checked that buf_size>0. |
| 1934 | if (aBuf[buf_size] == '\0') // It wrote at least one zero terminator (it might write more than one for Unicode, or if it's simply stored with more than one in the registry). |
| 1935 | { |
| 1936 | while (buf_size && !aBuf[buf_size - 1]) // Scan leftward in case more than one consecutive terminator. |
| 1937 | --buf_size; |
| 1938 | return buf_size; // There's a tiny chance that this could the wrong length, namely when the string contains binary zero(s) to the left of non-zero characters. But that seems too rare to be worth calling strlen() for. |
| 1939 | } |
| 1940 | // Otherwise, it didn't write a terminator, so provide one. |
| 1941 | ++buf_size; // To reflect the fact that we're about to write an extra char. |
| 1942 | if (buf_size >= aBufSize) // There's no room for a terminator without truncating the data (very rare). Seems best to indicate failure. |
| 1943 | { |
| 1944 | *aBuf = '\0'; |
| 1945 | return 0; |
| 1946 | } |
| 1947 | // Otherwise, there's room for the terminator. |
| 1948 | aBuf[buf_size] = '\0'; |
| 1949 | return buf_size; // There's a tiny chance that this could the wrong length, namely when the string contains binary zero(s) to the left of non-zero characters. But that seems too rare to be worth calling strlen() for. |
| 1950 | } |
| 1951 | |
| 1952 | |
| 1953 |
no outgoing calls
no test coverage detected