3 /* FIXME: Currently IsBadWritePtr is implemented using VirtualQuery which
4 does not seem to work properly for stack address space. */
5 /* kill `left-hand operand of comma expression has no effect' warning */
6 #define IsBadWritePtr(lp, n) ((DWORD)lp==n?0:0)
8 BOOL STDCALL _InternalLoadString
12 PUNICODE_STRING pwstrDest
19 unsigned l
= uID
% 16; /* (1) */
21 /* parameter validation */
22 if(IsBadWritePtr(pwstrDest
, sizeof(UNICODE_STRING
)))
24 SetLastError(ERROR_INVALID_PARAMETER
);
29 find the string table. String tables are created by grouping, 16 by 16, string
30 resources whose identifiers, divided by 16, have the same integer quotient.
31 Holes in the numbering are filled with zero-length strings. String table ids
32 (actual resource ids) start from 1. See (1) and (2)
34 /* TODO: some sort of cache, here, would be great */
35 hrsStringTable
= FindResourceW
38 MAKEINTRESOURCEW((uID
/ 16) + 1), /* (2) */
43 if(hrsStringTable
== NULL
) return FALSE
;
45 /* load the string table into memory */
46 hResource
= LoadResource((HMODULE
)hInstance
, hrsStringTable
);
49 if(hResource
== NULL
) return FALSE
;
51 /* lock the resource into memory */
52 pStringTable
= LockResource(hResource
);
55 if(pStringTable
== NULL
) return FALSE
;
58 string tables are packed Unicode Pascal strings. The first WCHAR contains the
59 length, in characters, of the current string. Zero-length strings, if any, are
60 placeholders for unused slots, and should therefore be considered non-present.
61 See also (3). Here, we walk all the strings before that of interest
63 for(i
= 0; i
< l
; ++ i
)
65 /* skip the length and the current string */
66 pStringTable
+= 1 + (*pStringTable
);
69 /* we've reached the string of interest */
70 if((*pStringTable
) == 0)
72 /* the string is empty (unallocated) */
73 SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND
);
77 /* string length in bytes */
78 pwstrDest
->Length
= pwstrDest
->MaximumLength
= (*pStringTable
) * sizeof(WCHAR
);
81 pwstrDest
->Buffer
= pStringTable
+ 1;
91 int STDCALL LoadStringA
99 UNICODE_STRING wstrResStr
;
103 /* parameter validation */
107 (IsBadWritePtr(lpBuffer
, nBufferMax
* sizeof(lpBuffer
[0])))
110 SetLastError(ERROR_INVALID_PARAMETER
);
114 /* get the UNICODE_STRING descriptor of the in-memory image of the string */
115 if(!_InternalLoadString(hInstance
, uID
, &wstrResStr
))
120 convert the string. The Unicode string may be in UTF-16 (multi-byte), so we
121 don't alter wstrResStr.Length, and let RtlUnicodeStringToAnsiString truncate
125 strBuf
.MaximumLength
= nBufferMax
* sizeof(CHAR
);
126 strBuf
.Buffer
= lpBuffer
;
128 retSize
= WideCharToMultiByte(CP_ACP
, 0, wstrResStr
.Buffer
, wstrResStr
.Length
/ sizeof(WCHAR
), strBuf
.Buffer
, strBuf
.MaximumLength
, NULL
, NULL
);
134 strBuf
.Length
= retSize
;
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
);
162 int STDCALL LoadStringW
170 UNICODE_STRING wstrResStr
;
173 /* parameter validation */
177 (IsBadWritePtr(lpBuffer
, nBufferMax
* sizeof(lpBuffer
[0])))
180 SetLastError(ERROR_INVALID_PARAMETER
);
184 /* get the UNICODE_STRING descriptor of the in-memory image of the string */
185 if(!_InternalLoadString(hInstance
, uID
, &wstrResStr
))
189 /* get the length in characters */
190 nStringLen
= wstrResStr
.Length
/ sizeof(WCHAR
);
192 /* the buffer must be enough to contain the string and the null terminator */
193 if(nBufferMax
< (nStringLen
+ 1))
194 /* otherwise, the string is truncated */
195 nStringLen
= nBufferMax
- 1;
197 /* copy the string */
198 memcpy(lpBuffer
, wstrResStr
.Buffer
, nStringLen
* sizeof(WCHAR
));
200 /* null-terminate it */
201 lpBuffer
[nStringLen
] = 0;