Skip to content

Commit f4d15a5

Browse files
committed
Added memory module resource loading API.
1 parent 132964d commit f4d15a5

File tree

2 files changed

+238
-0
lines changed

2 files changed

+238
-0
lines changed

MemoryModule.c

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
#include <windows.h>
3939
#include <winnt.h>
40+
#include <tchar.h>
4041
#ifdef DEBUG_OUTPUT
4142
#include <stdio.h>
4243
#endif
@@ -517,3 +518,208 @@ void MemoryFreeLibrary(HMEMORYMODULE mod)
517518
HeapFree(GetProcessHeap(), 0, module);
518519
}
519520
}
521+
522+
#define DEFAULT_LANGUAGE MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)
523+
524+
HMEMORYRSRC MemoryFindResource(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type)
525+
{
526+
return MemoryFindResourceEx(module, name, type, DEFAULT_LANGUAGE);
527+
}
528+
529+
static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry(
530+
void *root,
531+
PIMAGE_RESOURCE_DIRECTORY resources,
532+
LPCTSTR key)
533+
{
534+
PIMAGE_RESOURCE_DIRECTORY_ENTRY entries = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (resources + 1);
535+
PIMAGE_RESOURCE_DIRECTORY_ENTRY result = NULL;
536+
DWORD start;
537+
DWORD end;
538+
DWORD middle;
539+
540+
if (!IS_INTRESOURCE(key) && key[0] == _T('#')) {
541+
// special case: resource id given as string
542+
_TCHAR *endpos = NULL;
543+
long int tmpkey = (WORD) _tcstol((_TCHAR *) &key[1], &endpos, 10);
544+
if (tmpkey <= 0xffff && _tcslen(endpos) == 0) {
545+
key = MAKEINTRESOURCE(tmpkey);
546+
}
547+
}
548+
549+
// entries are stored as ordered list of named entries,
550+
// followed by an ordered list of id entries - we can do
551+
// a binary search to find faster...
552+
if (IS_INTRESOURCE(key)) {
553+
WORD check = (WORD) (POINTER_TYPE) key;
554+
start = resources->NumberOfNamedEntries;
555+
end = start + resources->NumberOfIdEntries;
556+
557+
while (end > start) {
558+
WORD entryName;
559+
middle = (start + end) >> 1;
560+
entryName = (WORD) entries[middle].Name;
561+
if (check < entryName) {
562+
end = middle;
563+
} else if (check > entryName) {
564+
start = middle;
565+
} else {
566+
result = &entries[middle];
567+
break;
568+
}
569+
}
570+
} else {
571+
start = 0;
572+
end = resources->NumberOfIdEntries;
573+
#ifndef _UNICODE
574+
_TCHAR *searchKey = NULL;
575+
int searchKeyLength = 0;
576+
#endif
577+
while (end > start) {
578+
// resource names are always stored using 16bit characters
579+
middle = (start + end) >> 1;
580+
PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF));
581+
int cmp;
582+
#ifndef _UNICODE
583+
if (searchKey == NULL || searchKeyLength < resourceString->Length) {
584+
void *tmp = realloc(searchKey, resourceString->Length);
585+
if (tmp == NULL) {
586+
break;
587+
}
588+
589+
searchKey = (_TCHAR *) tmp;
590+
}
591+
wcstombs(searchKey, resourceString->NameString, resourceString->Length);
592+
cmp = strncmp(key, searchKey, resourceString->Length);
593+
#else
594+
cmp = wcsncmp((_TCHAR *) key, resourceString->NameString, resourceString->Length);
595+
#endif
596+
if (cmp < 0) {
597+
end = middle;
598+
} else if (cmp > 0) {
599+
start = middle;
600+
} else {
601+
result = &entries[middle];
602+
break;
603+
}
604+
}
605+
#ifndef _UNICODE
606+
free(searchKey);
607+
#endif
608+
}
609+
610+
611+
return result;
612+
}
613+
614+
HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type, WORD language)
615+
{
616+
unsigned char *codeBase = ((PMEMORYMODULE) module)->codeBase;
617+
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE) module, IMAGE_DIRECTORY_ENTRY_RESOURCE);
618+
PIMAGE_RESOURCE_DIRECTORY rootResources;
619+
PIMAGE_RESOURCE_DIRECTORY nameResources;
620+
PIMAGE_RESOURCE_DIRECTORY typeResources;
621+
PIMAGE_RESOURCE_DIRECTORY_ENTRY foundType;
622+
PIMAGE_RESOURCE_DIRECTORY_ENTRY foundName;
623+
PIMAGE_RESOURCE_DIRECTORY_ENTRY foundLanguage;
624+
if (directory->Size == 0) {
625+
// no resource table found
626+
SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
627+
return NULL;
628+
}
629+
630+
if (language == DEFAULT_LANGUAGE) {
631+
// use language from current thread
632+
language = LANGIDFROMLCID(GetThreadLocale());
633+
}
634+
635+
// resources are stored as three-level tree
636+
// - first node is the type
637+
// - second node is the name
638+
// - third node is the language
639+
rootResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress);
640+
foundType = _MemorySearchResourceEntry(rootResources, rootResources, type);
641+
if (foundType == NULL) {
642+
SetLastError(ERROR_RESOURCE_TYPE_NOT_FOUND);
643+
return NULL;
644+
}
645+
646+
typeResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress + (foundType->OffsetToData & 0x7fffffff));
647+
foundName = _MemorySearchResourceEntry(rootResources, typeResources, name);
648+
if (foundName == NULL) {
649+
SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND);
650+
return NULL;
651+
}
652+
653+
nameResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress + (foundName->OffsetToData & 0x7fffffff));
654+
foundLanguage = _MemorySearchResourceEntry(rootResources, nameResources, (LPCTSTR) (POINTER_TYPE) language);
655+
if (foundLanguage == NULL) {
656+
// requested language not found, use first available
657+
if (nameResources->NumberOfIdEntries == 0) {
658+
SetLastError(ERROR_RESOURCE_LANG_NOT_FOUND);
659+
return NULL;
660+
}
661+
662+
foundLanguage = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (nameResources + 1);
663+
}
664+
665+
return (codeBase + directory->VirtualAddress + (foundLanguage->OffsetToData & 0x7fffffff));
666+
}
667+
668+
DWORD MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource)
669+
{
670+
PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource;
671+
672+
return entry->Size;
673+
}
674+
675+
LPVOID MemoryLoadResource(HMEMORYMODULE module, HMEMORYRSRC resource)
676+
{
677+
unsigned char *codeBase = ((PMEMORYMODULE) module)->codeBase;
678+
PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource;
679+
680+
return codeBase + entry->OffsetToData;
681+
}
682+
683+
int
684+
MemoryLoadString(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize)
685+
{
686+
return MemoryLoadStringEx(module, id, buffer, maxsize, DEFAULT_LANGUAGE);
687+
}
688+
689+
int
690+
MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WORD language)
691+
{
692+
if (maxsize == 0) {
693+
return 0;
694+
}
695+
696+
HMEMORYRSRC resource = MemoryFindResourceEx(module, MAKEINTRESOURCE((id >> 4) + 1), RT_STRING, language);
697+
if (resource == NULL) {
698+
buffer[0] = 0;
699+
return 0;
700+
}
701+
702+
PIMAGE_RESOURCE_DIR_STRING_U data = MemoryLoadResource(module, resource);
703+
id = id & 0x0f;
704+
while (id--) {
705+
data = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) data) + (data->Length + 1) * sizeof(WCHAR));
706+
}
707+
if (data->Length == 0) {
708+
SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND);
709+
buffer[0] = 0;
710+
return 0;
711+
}
712+
713+
DWORD size = data->Length;
714+
if (size >= maxsize) {
715+
size = maxsize;
716+
} else {
717+
buffer[size] = 0;
718+
}
719+
#ifdef _UNICODE
720+
_tcsncpy(buffer, data->NameString, size);
721+
#else
722+
wcstombs(buffer, data->NameString, size);
723+
#endif
724+
return size;
725+
}

MemoryModule.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
typedef void *HMEMORYMODULE;
3333

34+
typedef void *HMEMORYRSRC;
35+
3436
typedef void *HCUSTOMMODULE;
3537

3638
#ifdef __cplusplus
@@ -70,6 +72,36 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR);
7072
*/
7173
void MemoryFreeLibrary(HMEMORYMODULE);
7274

75+
/**
76+
* Find the location of a resource with the specified type and name.
77+
*/
78+
HMEMORYRSRC MemoryFindResource(HMEMORYMODULE, LPCTSTR, LPCTSTR);
79+
80+
/**
81+
* Find the location of a resource with the specified type, name and language.
82+
*/
83+
HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE, LPCTSTR, LPCTSTR, WORD);
84+
85+
/**
86+
* Get the size of the resource in bytes.
87+
*/
88+
DWORD MemorySizeofResource(HMEMORYMODULE, HMEMORYRSRC);
89+
90+
/**
91+
* Get a pointer to the contents of the resource.
92+
*/
93+
LPVOID MemoryLoadResource(HMEMORYMODULE, HMEMORYRSRC);
94+
95+
/**
96+
* Load a string resource.
97+
*/
98+
int MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int);
99+
100+
/**
101+
* Load a string resource with a given language.
102+
*/
103+
int MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD);
104+
73105
#ifdef __cplusplus
74106
}
75107
#endif

0 commit comments

Comments
 (0)