xref: /reactos/dll/cpl/desk/muireg.c (revision 01e5cb0c)
1 #include "desk.h"
2 
3 /******************************************************************************
4  * load_string [Internal]
5  *
6  * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
7  * avoid importing user32, which is higher level than advapi32. Helper for
8  * RegLoadMUIString.
9  */
10 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
11 {
12     HGLOBAL hMemory;
13     HRSRC hResource;
14     WCHAR *pString;
15     int idxString;
16 
17     /* Negative values have to be inverted. */
18     if (HIWORD(resId) == 0xffff)
19         resId = (UINT)(-((INT)resId));
20 
21     /* Load the resource into memory and get a pointer to it. */
22     hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
23     if (!hResource) return 0;
24     hMemory = LoadResource(hModule, hResource);
25     if (!hMemory) return 0;
26     pString = LockResource(hMemory);
27 
28     /* Strings are length-prefixed. Lowest nibble of resId is an index. */
29     idxString = resId & 0xf;
30     while (idxString--) pString += *pString + 1;
31 
32     /* If no buffer is given, return length of the string. */
33     if (!pwszBuffer) return *pString;
34 
35     /* Else copy over the string, respecting the buffer size. */
36     cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
37     if (cMaxChars >= 0)
38     {
39         memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
40         pwszBuffer[cMaxChars] = L'\0';
41     }
42 
43     return cMaxChars;
44 }
45 
46 
47 /************************************************************************
48  *  RegLoadMUIStringW
49  *
50  * @implemented
51  */
52 LONG
53 RegLoadMUIStringW(IN HKEY hKey,
54                   IN LPCWSTR pszValue  OPTIONAL,
55                   OUT LPWSTR pszOutBuf,
56                   IN DWORD cbOutBuf,
57                   OUT LPDWORD pcbData OPTIONAL,
58                   IN DWORD Flags,
59                   IN LPCWSTR pszDirectory  OPTIONAL)
60 {
61     DWORD dwValueType, cbData;
62     LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
63     LONG result;
64 
65     /* Parameter sanity checks. */
66     if (!hKey || !pszOutBuf)
67         return ERROR_INVALID_PARAMETER;
68 
69     if (pszDirectory && *pszDirectory)
70     {
71         //FIXME("BaseDir parameter not yet supported!\n");
72         return ERROR_INVALID_PARAMETER;
73     }
74 
75     /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
76     result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData);
77     if (result != ERROR_SUCCESS) goto cleanup;
78     if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData)
79     {
80         result = ERROR_FILE_NOT_FOUND;
81         goto cleanup;
82     }
83     pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
84     if (!pwszTempBuffer)
85     {
86         result = ERROR_NOT_ENOUGH_MEMORY;
87         goto cleanup;
88     }
89     result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
90     if (result != ERROR_SUCCESS) goto cleanup;
91 
92     /* Expand environment variables, if appropriate, or copy the original string over. */
93     if (dwValueType == REG_EXPAND_SZ)
94     {
95         cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
96         if (!cbData) goto cleanup;
97         pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
98         if (!pwszExpandedBuffer)
99         {
100             result = ERROR_NOT_ENOUGH_MEMORY;
101             goto cleanup;
102         }
103         ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
104     }
105     else
106     {
107         pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
108         memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
109     }
110 
111     /* If the value references a resource based string, parse the value and load the string.
112      * Else just copy over the original value. */
113     result = ERROR_SUCCESS;
114     if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */
115     {
116         lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR));
117     }
118     else
119     {
120         WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L',');
121         UINT uiStringId;
122         HMODULE hModule;
123 
124         /* Format of the expanded value is 'path_to_dll,-resId' */
125         if (!pComma || pComma[1] != L'-')
126         {
127             result = ERROR_BADKEY;
128             goto cleanup;
129         }
130 
131         uiStringId = _wtoi(pComma+2);
132         *pComma = L'\0';
133 
134         hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE);
135         if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR)))
136             result = ERROR_BADKEY;
137         FreeLibrary(hModule);
138     }
139 
140 cleanup:
141     HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
142     HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
143     return result;
144 }
145