- Add Wine implementation LoadStringA/W. This is fixed all wine tests for LoadString

svn path=/trunk/; revision=38652
This commit is contained in:
Dmitry Chapyshev 2009-01-08 19:47:29 +00:00
parent 915dfcf6a7
commit c76d2abb9d

View file

@ -20,223 +20,85 @@ typedef DWORD (WINAPI *CMP_UNREGNOTIFY) (ULONG );
static HINSTANCE hSetupApi = NULL;
BOOL
/*
* @implemented (Synced with Wine 08.01.2009)
*/
int
WINAPI
_InternalLoadString(HINSTANCE hInstance,
UINT uID,
PUNICODE_STRING pwstrDest)
LoadStringA(HINSTANCE instance, UINT resource_id, LPSTR buffer, INT buflen)
{
HRSRC hrsStringTable;
HGLOBAL hResource;
PWCHAR pStringTable;
unsigned i;
unsigned l = uID % 16; /* (1) */
HGLOBAL hmem;
HRSRC hrsrc;
DWORD retval = 0;
/* parameter validation */
if (IsBadWritePtr(pwstrDest, sizeof(UNICODE_STRING)))
if (!buflen) return -1;
/* Use loword (incremented by 1) as resourceid */
if ((hrsrc = FindResourceW( instance, MAKEINTRESOURCEW((LOWORD(resource_id) >> 4) + 1),
(LPWSTR)RT_STRING )) &&
(hmem = LoadResource( instance, hrsrc )))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
const WCHAR *p = LockResource(hmem);
unsigned int id = resource_id & 0x000f;
while (id--) p += *p + 1;
RtlUnicodeToMultiByteN( buffer, buflen - 1, &retval, (PWSTR)(p + 1), *p * sizeof(WCHAR) );
}
/*
find the string table. String tables are created by grouping, 16 by 16, string
resources whose identifiers, divided by 16, have the same integer quotient.
Holes in the numbering are filled with zero-length strings. String table ids
(actual resource ids) start from 1. See (1) and (2)
*/
/* TODO: some sort of cache, here, would be great */
hrsStringTable = FindResourceW((HMODULE)hInstance,
MAKEINTRESOURCEW((uID / 16) + 1), /* (2) */
RT_STRING);
/* failure */
if (hrsStringTable == NULL) return FALSE;
/* load the string table into memory */
hResource = LoadResource((HMODULE)hInstance, hrsStringTable);
/* failure */
if (hResource == NULL) return FALSE;
/* lock the resource into memory */
pStringTable = LockResource(hResource);
/* failure */
if (pStringTable == NULL) return FALSE;
/*
string tables are packed Unicode Pascal strings. The first WCHAR contains the
length, in characters, of the current string. Zero-length strings, if any, are
placeholders for unused slots, and should therefore be considered non-present.
See also (3). Here, we walk all the strings before that of interest
*/
for(i = 0; i < l; ++ i)
{
/* skip the length and the current string */
pStringTable += 1 + (*pStringTable);
}
/* we've reached the string of interest */
if ((*pStringTable) == 0)
{
/* the string is empty (unallocated) */
SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND);
return FALSE; /* 3 */
}
/* string length in bytes */
pwstrDest->Length = pwstrDest->MaximumLength = (*pStringTable) * sizeof(WCHAR);
/* string */
pwstrDest->Buffer = pStringTable + 1;
/* success */
return TRUE;
buffer[retval] = 0;
return retval;
}
/*
* @implemented
* @implemented (Synced with Wine 08.01.2009)
*/
int
WINAPI
LoadStringA(HINSTANCE hInstance,
UINT uID,
LPSTR lpBuffer,
int nBufferMax)
LoadStringW(HINSTANCE instance, UINT resource_id, LPWSTR buffer, INT buflen)
{
UNICODE_STRING wstrResStr;
ANSI_STRING strBuf;
INT retSize;
HGLOBAL hmem;
HRSRC hrsrc;
WCHAR *p;
int string_num;
int i;
/* parameter validation */
if(buffer == NULL)
return 0;
if (nBufferMax < 1)
/* Use loword (incremented by 1) as resourceid */
hrsrc = FindResourceW( instance, MAKEINTRESOURCEW((LOWORD(resource_id) >> 4) + 1),
(LPWSTR)RT_STRING );
if (!hrsrc) return 0;
hmem = LoadResource( instance, hrsrc );
if (!hmem) return 0;
p = LockResource(hmem);
string_num = resource_id & 0x000f;
for (i = 0; i < string_num; i++)
p += *p + 1;
/*if buflen == 0, then return a read-only pointer to the resource itself in buffer
it is assumed that buffer is actually a (LPWSTR *) */
if(buflen == 0)
{
return -1;
*((LPWSTR *)buffer) = p + 1;
return *p;
}
if (IsBadWritePtr(lpBuffer, nBufferMax * sizeof(lpBuffer[0])))
{
SetLastError(ERROR_INVALID_PARAMETER);
i = min(buflen - 1, *p);
if (i > 0) {
memcpy(buffer, p + 1, i * sizeof (WCHAR));
buffer[i] = 0;
} else {
if (buflen > 1) {
buffer[0] = 0;
return 0;
}
/* get the UNICODE_STRING descriptor of the in-memory image of the string */
if (!_InternalLoadString(hInstance, uID, &wstrResStr))
{
/* failure */
return 0;
}
/*
convert the string. The Unicode string may be in UTF-16 (multi-byte), so we
don't alter wstrResStr.Length, and let RtlUnicodeStringToAnsiString truncate
it, if necessary
*/
strBuf.Length = 0;
strBuf.MaximumLength = nBufferMax * sizeof(CHAR);
strBuf.Buffer = lpBuffer;
retSize = WideCharToMultiByte(CP_ACP,
0,
wstrResStr.Buffer,
wstrResStr.Length / sizeof(WCHAR),
strBuf.Buffer,
strBuf.MaximumLength,
NULL,
NULL);
if (!retSize)
{
/* failure */
return 0;
}
else
{
strBuf.Length = retSize;
}
/* the ANSI string may not be null-terminated */
if (strBuf.Length >= strBuf.MaximumLength)
{
/* length greater than the buffer? whatever */
int nStringLen = strBuf.MaximumLength / sizeof(CHAR) - 1;
/* zero the last character in the buffer */
strBuf.Buffer[nStringLen] = 0;
/* success */
return nStringLen;
}
else
{
/* zero the last character in the string */
strBuf.Buffer[strBuf.Length / sizeof(CHAR)] = 0;
/* success */
return strBuf.Length / sizeof(CHAR);
}
}
/*
* @implemented
*/
int
WINAPI
LoadStringW(HINSTANCE hInstance,
UINT uID,
LPWSTR lpBuffer,
int nBufferMax)
{
UNICODE_STRING wstrResStr;
int nStringLen;
/* parameter validation */
if ((nBufferMax < 0) || (lpBuffer == NULL) ||
((nBufferMax > 0) && IsBadWritePtr(lpBuffer, nBufferMax * sizeof(lpBuffer[0]))) ||
/* undocumented: If nBufferMax is 0, LoadStringW will copy a pointer to the
in-memory image of the string to the specified buffer and return the length
of the string in WCHARs */
((nBufferMax == 0) && IsBadWritePtr(lpBuffer, sizeof(lpBuffer))))
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
/* get the UNICODE_STRING descriptor of the in-memory image of the string */
if (!_InternalLoadString(hInstance, uID, &wstrResStr))
{
/* failure */
return 0;
}
/* get the length in characters */
nStringLen = wstrResStr.Length / sizeof(WCHAR);
if (nBufferMax > 0)
{
/* the buffer must be enough to contain the string and the null terminator */
if (nBufferMax < (nStringLen + 1))
{
/* otherwise, the string is truncated */
nStringLen = nBufferMax - 1;
}
/* copy the string */
memcpy(lpBuffer, wstrResStr.Buffer, nStringLen * sizeof(WCHAR));
/* null-terminate it */
lpBuffer[nStringLen] = 0;
}
else
{
*((LPWSTR*)lpBuffer) = wstrResStr.Buffer;
}
/* success */
return nStringLen;
return i;
}