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 = FindResource
41 MAKEINTRESOURCE((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;
90 int STDCALL LoadStringA
98 UNICODE_STRING wstrResStr;
102 /* parameter validation */
106 (IsBadWritePtr(lpBuffer, nBufferMax * sizeof(lpBuffer[0])))
109 SetLastError(ERROR_INVALID_PARAMETER);
113 /* get the UNICODE_STRING descriptor of the in-memory image of the string */
114 if(!_InternalLoadString(hInstance, uID, &wstrResStr))
119 convert the string. The Unicode string may be in UTF-16 (multi-byte), so we
120 don't alter wstrResStr.Length, and let RtlUnicodeStringToAnsiString truncate
124 strBuf.MaximumLength = nBufferMax * sizeof(CHAR);
125 strBuf.Buffer = lpBuffer;
127 nErrCode = RtlUnicodeStringToAnsiString(&strBuf, &wstrResStr, FALSE);
129 if(!NT_SUCCESS(nErrCode))
132 RtlNtStatusToDosError(nErrCode);
136 /* the ANSI string may not be null-terminated */
137 if(strBuf.Length >= strBuf.MaximumLength)
139 /* length greater than the buffer? whatever */
140 int nStringLen = strBuf.MaximumLength / sizeof(CHAR) - 1;
142 /* zero the last character in the buffer */
143 strBuf.Buffer[nStringLen] = 0;
150 /* zero the last character in the string */
151 strBuf.Buffer[strBuf.Length / sizeof(CHAR)] = 0;
154 return strBuf.Length / sizeof(CHAR);
158 int STDCALL LoadStringW
166 UNICODE_STRING wstrResStr;
169 /* parameter validation */
173 (IsBadWritePtr(lpBuffer, nBufferMax * sizeof(lpBuffer[0])))
176 SetLastError(ERROR_INVALID_PARAMETER);
180 /* get the UNICODE_STRING descriptor of the in-memory image of the string */
181 if(!_InternalLoadString(hInstance, uID, &wstrResStr))
185 /* get the length in characters */
186 nStringLen = wstrResStr.Length / sizeof(WCHAR);
188 /* the buffer must be enough to contain the string and the null terminator */
189 if(nBufferMax < (nStringLen + 1))
190 /* otherwise, the string is truncated */
191 nStringLen = nBufferMax - 1;
193 /* copy the string */
194 memcpy(lpBuffer, wstrResStr.Buffer, nStringLen * sizeof(WCHAR));
196 /* null-terminate it */
197 lpBuffer[nStringLen] = 0;