4 #include <kernel32/error.h>
6 BOOL STDCALL _InternalLoadString
10 PUNICODE_STRING pwstrDest
16 unsigned l = uID % 16; /* (1) */
18 /* parameter validation */
19 if(IsBadWritePtr(pwstrDest, sizeof(UNICODE_STRING)))
21 SetLastError(ERROR_INVALID_PARAMETER);
26 find the string table. String tables are created by grouping, 16 by 16, string
27 resources whose identifiers, divided by 16, have the same integer quotient.
28 Holes in the numbering are filled with zero-length strings. String table ids
29 (actual resource ids) start from 1. See (1) and (2)
31 /* TODO: some sort of cache, here, would be great */
32 hrsStringTable = FindResource
35 MAKEINTRESOURCE((uID / 16) + 1), /* (2) */
40 if(hrsStringTable == NULL) return FALSE;
42 /* load the string table into memory */
43 pStringTable = LoadResource((HMODULE)hInstance, hrsStringTable);
46 if(pStringTable == NULL) return FALSE;
49 string tables are packed Unicode Pascal strings. The first WCHAR contains the
50 length, in characters, of the current string. Zero-length strings, if any, are
51 placeholders for unused slots, and should therefore be considered non-present.
52 See also (3). Here, we walk all the strings before that of interest
54 for(i = 0; i < l; ++ i)
56 /* skip the length and the current string */
57 pStringTable += 1 + (*pStringTable);
60 /* we've reached the string of interest */
61 if((*pStringTable) == 0)
63 /* the string is empty (unallocated) */
64 SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND);
69 pwstrDest->Length = pwstrDest->MaximumLength = (*pStringTable);
72 pwstrDest->Buffer = pStringTable + 1;
78 int STDCALL LoadStringA
86 UNICODE_STRING wstrResStr;
90 /* parameter validation */
94 (IsBadWritePtr(lpBuffer, nBufferMax * sizeof(lpBuffer[0])))
97 SetLastError(ERROR_INVALID_PARAMETER);
101 /* get the UNICODE_STRING descriptor of the in-memory image of the string */
102 if(!_InternalLoadString(hInstance, uID, &wstrResStr))
107 convert the string. The Unicode string may be in UTF-16 (multi-byte), so we
108 don't alter wstrResStr.Length, and let RtlUnicodeStringToAnsiString truncate
112 strBuf.MaximumLength = nBufferMax * sizeof(CHAR);
113 strBuf.Buffer = lpBuffer;
115 nErrCode = RtlUnicodeStringToAnsiString(&strBuf, &wstrResStr, FALSE);
117 if(!NT_SUCCESS(nErrCode))
120 SetLastErrorByStatus(nErrCode);
124 /* the ANSI string may not be null-terminated */
125 if(strBuf.Length >= strBuf.MaximumLength)
127 /* length greater than the buffer? whatever */
128 int nStringLen = strBuf.MaximumLength / sizeof(CHAR) - 1;
130 /* zero the last character in the buffer */
131 strBuf.Buffer[nStringLen] = 0;
138 /* zero the last character in the string */
139 strBuf.Buffer[strBuf.Length / sizeof(CHAR)] = 0;
142 return strBuf.Length / sizeof(CHAR);
146 int STDCALL LoadStringW
154 UNICODE_STRING wstrResStr;
157 /* parameter validation */
161 (IsBadWritePtr(lpBuffer, nBufferMax * sizeof(lpBuffer[0])))
164 SetLastError(ERROR_INVALID_PARAMETER);
168 /* get the UNICODE_STRING descriptor of the in-memory image of the string */
169 if(!_InternalLoadString(hInstance, uID, &wstrResStr))
173 /* get the length in characters */
174 nStringLen = wstrResStr.Length / sizeof(WCHAR);
176 /* the buffer must be enough to contain the string and the null terminator */
177 if(nBufferMax < (nStringLen + 1))
178 /* otherwise, the string is truncated */
179 nStringLen = nBufferMax - 1;
181 /* copy the string */
182 memcpy(lpBuffer, wstrResStr.Buffer, nStringLen * sizeof(WCHAR));
184 /* null-terminate it */
185 lpBuffer[nStringLen] = 0;