4 #include <kernel32/error.h>
6 /* FIXME: Currently IsBadWritePtr is implemented using VirtualQuery which
7 does not seem to work properly for stack address space. */
8 /* kill `left-hand operand of comma expression has no effect' warning */
9 #define IsBadWritePtr(lp, n) ((DWORD)lp==n?0:0)
11 BOOL STDCALL _InternalLoadString
15 PUNICODE_STRING pwstrDest
22 unsigned l = uID % 16; /* (1) */
24 /* parameter validation */
25 if(IsBadWritePtr(pwstrDest, sizeof(UNICODE_STRING)))
27 SetLastError(ERROR_INVALID_PARAMETER);
32 find the string table. String tables are created by grouping, 16 by 16, string
33 resources whose identifiers, divided by 16, have the same integer quotient.
34 Holes in the numbering are filled with zero-length strings. String table ids
35 (actual resource ids) start from 1. See (1) and (2)
37 /* TODO: some sort of cache, here, would be great */
38 hrsStringTable = FindResourceW
41 MAKEINTRESOURCEW((uID / 16) + 1), /* (2) */
46 if(hrsStringTable == NULL) return FALSE;
48 /* load the string table into memory */
49 hResource = LoadResource((HMODULE)hInstance, hrsStringTable);
52 if(hResource == NULL) return FALSE;
54 /* lock the resource into memory */
55 pStringTable = LockResource(hResource);
58 if(pStringTable == NULL) return FALSE;
61 string tables are packed Unicode Pascal strings. The first WCHAR contains the
62 length, in characters, of the current string. Zero-length strings, if any, are
63 placeholders for unused slots, and should therefore be considered non-present.
64 See also (3). Here, we walk all the strings before that of interest
66 for(i = 0; i < l; ++ i)
68 /* skip the length and the current string */
69 pStringTable += 1 + (*pStringTable);
72 /* we've reached the string of interest */
73 if((*pStringTable) == 0)
75 /* the string is empty (unallocated) */
76 SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND);
80 /* string length in bytes */
81 pwstrDest->Length = pwstrDest->MaximumLength = (*pStringTable) * sizeof(WCHAR);
84 pwstrDest->Buffer = pStringTable + 1;
94 int STDCALL LoadStringA
102 UNICODE_STRING wstrResStr;
106 /* parameter validation */
110 (IsBadWritePtr(lpBuffer, nBufferMax * sizeof(lpBuffer[0])))
113 SetLastError(ERROR_INVALID_PARAMETER);
117 /* get the UNICODE_STRING descriptor of the in-memory image of the string */
118 if(!_InternalLoadString(hInstance, uID, &wstrResStr))
123 convert the string. The Unicode string may be in UTF-16 (multi-byte), so we
124 don't alter wstrResStr.Length, and let RtlUnicodeStringToAnsiString truncate
128 strBuf.MaximumLength = nBufferMax * sizeof(CHAR);
129 strBuf.Buffer = lpBuffer;
131 nErrCode = RtlUnicodeStringToAnsiString(&strBuf, &wstrResStr, FALSE);
133 if(!NT_SUCCESS(nErrCode))
136 RtlNtStatusToDosError(nErrCode);
140 /* the ANSI string may not be null-terminated */
141 if(strBuf.Length >= strBuf.MaximumLength)
143 /* length greater than the buffer? whatever */
144 int nStringLen = strBuf.MaximumLength / sizeof(CHAR) - 1;
146 /* zero the last character in the buffer */
147 strBuf.Buffer[nStringLen] = 0;
154 /* zero the last character in the string */
155 strBuf.Buffer[strBuf.Length / sizeof(CHAR)] = 0;
158 return strBuf.Length / sizeof(CHAR);
166 int STDCALL LoadStringW
174 UNICODE_STRING wstrResStr;
177 /* parameter validation */
181 (IsBadWritePtr(lpBuffer, nBufferMax * sizeof(lpBuffer[0])))
184 SetLastError(ERROR_INVALID_PARAMETER);
188 /* get the UNICODE_STRING descriptor of the in-memory image of the string */
189 if(!_InternalLoadString(hInstance, uID, &wstrResStr))
193 /* get the length in characters */
194 nStringLen = wstrResStr.Length / sizeof(WCHAR);
196 /* the buffer must be enough to contain the string and the null terminator */
197 if(nBufferMax < (nStringLen + 1))
198 /* otherwise, the string is truncated */
199 nStringLen = nBufferMax - 1;
201 /* copy the string */
202 memcpy(lpBuffer, wstrResStr.Buffer, nStringLen * sizeof(WCHAR));
204 /* null-terminate it */
205 lpBuffer[nStringLen] = 0;