将 GetUILanguageFallbackList API 与 MinGW-w64 链接

问题描述 投票:0回答:1

我正在尝试将 Windows

GetUILanguageFallbackList
API 与 MinGW-w64 一起使用。

这是一个非常简单的调用 API 的示例:

#include <windows.h>
#include <muiload.h>

int main() {
    GetUILanguageFallbackList(NULL, 0, NULL);
    return 0;
}

现在,我并不期望该代码实际上能做任何有用的事情,因为我还没有提供有效的参数组合。但此时我要做的就是编译和链接代码。我实际上有一个更长的示例,尝试正确使用 API,但我创建了上述最小版本只是为了重现我的链接问题。所以我将其保存为

uilang0.c

但是当我尝试编译时,链接失败并出现以下错误:

# gcc -o uilang0 uilang0.c
C:/tools/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\tools\msys64\tmp\cclvYTlj.o:uilang0.c:(.text+0x1e): undefined reference to `GetUILanguageFallbackList'
collect2.exe: error: ld returned 1 exit status

Windows SDK 中有一个

muiload.lib
,但我找不到 MinGW-w64 的等效项,即使它确实提供了
muiload.h
头文件。我尝试与之联系;修复了上述链接器错误,但引入了更多链接器错误:

# gcc -o uilang0 uilang0.c /c/Program\ Files\ \(x86\)/Windows\ Kits/10/Lib/10.0.22621.0/um/x64/muiload.lib
C:/tools/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/Program Files (x86)/Windows Kits/10/Lib/10.0.22621.0/um/x64/muiload.lib(d:/os/obj/amd64fre/minkernel/crts/crtw32/misc/nt/objfre/amd64/guard_support.obj):(.00cfg[__guard_check_icall_fptr]+0x0): undefined reference to `_guard_check_icall_nop'
C:/tools/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/Program Files (x86)/Windows Kits/10/Lib/10.0.22621.0/um/x64/muiload.lib(d:/os/obj/amd64fre/minkernel/crts/crtw32/misc/nt/objfre/amd64/guard_support.obj):(.00cfg[__guard_xfg_check_icall_fptr]+0x0): undefined reference to `_guard_check_icall_nop'
C:/tools/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/Program Files (x86)/Windows Kits/10/Lib/10.0.22621.0/um/x64/muiload.lib(d:/os/obj/amd64fre/onecore/base/mui/muiload/lib/objfre/amd64/getuilanguagefallbacklist.obj):(.text$mn+0xe): undefined reference to `__security_cookie'
C:/tools/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/Program Files (x86)/Windows Kits/10/Lib/10.0.22621.0/um/x64/muiload.lib(d:/os/obj/amd64fre/onecore/base/mui/muiload/lib/objfre/amd64/getuilanguagefallbacklist.obj):(.text$mn+0x92): undefined reference to `__security_check_cookie'
C:/tools/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/Program Files (x86)/Windows Kits/10/Lib/10.0.22621.0/um/x64/muiload.lib(d:/os/obj/amd64fre/onecore/base/mui/muiload/lib/objfre/amd64/getuilanguagefallbacklist.obj):(.text$mn+0x13): undefined reference to `__security_cookie'
C:/tools/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/Program Files (x86)/Windows Kits/10/Lib/10.0.22621.0/um/x64/muiload.lib(d:/os/obj/amd64fre/onecore/base/mui/muiload/lib/objfre/amd64/getuilanguagefallbacklist.obj):(.text$mn+0xfb): undefined reference to `__security_check_cookie'
C:/tools/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/Program Files (x86)/Windows Kits/10/Lib/10.0.22621.0/um/x64/muiload.lib(d:/os/obj/amd64fre/onecore/base/mui/muiload/lib/objfre/amd64/getuilanguagefallbacklist.obj):(.xdata[$unwind$?PreVistaFallback@@YAHKPEAKPEAG0@Z]+0x14): undefined reference to `__GSHandlerCheck'
C:/tools/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/Program Files (x86)/Windows Kits/10/Lib/10.0.22621.0/um/x64/muiload.lib(d:/os/obj/amd64fre/onecore/base/mui/muiload/lib/objfre/amd64/getuilanguagefallbacklist.obj):(.xdata[$unwind$?MultiStr_AddLangAndParentNames@@YAHPEAG_KG@Z]+0x10): undefined reference to `__GSHandlerCheck'
C:/tools/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/Program Files (x86)/Windows Kits/10/Lib/10.0.22621.0/um/x64/muiload.lib(d:/os/obj/amd64fre/onecore/base/mui/muiload/lib/objfre/amd64/multistr.obj):(.text$mn+0x7f): undefined reference to `StringCchCopyW'
collect2.exe: error: ld returned 1 exit status

我尝试添加更多 Platform SDK

.lib
文件,但无论我使用什么组合,我仍然得到未定义的引用。添加
BufferOverflowU.lib
可以消除对
__security_cookie
/
__security_check_cookie
的未定义引用。添加
ntdllp.lib
可以消除对
__GSHandlerCheck
的未定义引用。但我似乎无法摆脱
_guard_check_icall_nop
StringCchCopyW
未定义的引用。另外,我忍不住担心在不知道自己在做什么的情况下随机添加库,即使我最终将其链接起来,它也可能由于某些不兼容的组合而无法工作。

更新:如果我创建文件

fakeapi.c
,其内容为:

#define DEPRECATE_SUPPORTED
#include <strsafe.h>

__attribute__((weak))
STRSAFEAPI StringCchCopyW(STRSAFE_LPWSTR pszDest,size_t cchDest,STRSAFE_LPCWSTR pszSrc) {
  if(cchDest > STRSAFE_MAX_CCH) return STRSAFE_E_INVALID_PARAMETER;
  return StringCopyWorkerW(pszDest,cchDest,pszSrc);
}

__attribute__((fastcall))
extern void _guard_check_icall_nop(uintptr_t Target) {
  ((void)Target);
}

然后做:

gcc -o uilang0 uilang0.c \
    /c/Program\ Files\ \(x86\)/Windows\ Kits/10/Lib/10.0.22621.0/um/x64/{muiload,BufferOverflowU,ntdllp}.lib \
    fakeapi.c

这似乎克服了链接时的所有

undefined reference
错误。但是,编译仍然失败:

C:/tools/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: uilang0.exe:.retplne: section below image base

我猜要解决这个问题,我需要调整链接器脚本来设置

.retplne
部分的基地址。检查默认链接器脚本(使用
-Wl,--verbose
)我没有看到任何提及的
.retplne
部分。所以我尝试添加
-Wl,--section-start=.retplne=0x141000000
。这样,链接成功,但尝试运行结果
.exe
失败。

c winapi mingw-w64
1个回答
0
投票

Hacky,但我成功了:

gcc -o uilang0.exe uilang0.c \
    /c/Program\ Files\ \(x86\)/Windows\ Kits/10/Lib/10.0.22621.0/um/x64/{muiload,BufferOverflowU,ntdllp}.lib \
    fakeapi.c \
    -Wl,--section-start=.retplne=0x141000000

产生的

uilang0.exe
不起作用。但是,让我们使用
objcopy
对其进行编辑以删除
.retplne
部分:

objcopy --remove-section=.retplne ./uilang0.exe

可能应该将链接器脚本编辑为

objcopy --remove-section=
DISCARD
部分,而不是使用
.retplne

结果

uilang0.exe
执行成功。此外,
GetUILanguageFallbackList
API 确实有效,如下面的
uilang0.c
增强版所示:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdnoreturn.h>
#include <string.h>
#include <muiload.h>

noreturn void fatal(const char* msg) {
    fprintf(stderr, "FATAL: %s\n", msg);
    exit(1);
}

noreturn void fatal_error(const char* op) {
    fprintf(stderr, "FATAL: %s failed with error: %lu\n", op, GetLastError());
    exit(1);
}

void* xmalloc(size_t size) {
    void* ptr = malloc(size);
    if (ptr == NULL) fatal("memory allocation failed");
    return ptr;
}

void *xrealloc(void* ptr, size_t size) {
    ptr = realloc(ptr, size);
    if (ptr == NULL) fatal("memory allocation failed");
    return ptr;
}

char* ConvertUTF16ToUTF8(const wchar_t* utf16Str) {
    int utf8Len = WideCharToMultiByte(CP_UTF8, 0, utf16Str, -1, NULL, 0, NULL, NULL);
    if (utf8Len == 0) return NULL;
    char* utf8Str = (char*)xmalloc(utf8Len);
    WideCharToMultiByte(CP_UTF8, 0, utf16Str, -1, utf8Str, utf8Len, NULL, NULL);
    return utf8Str;
}

int main() {
    ULONG bufferSize = 256;
    wchar_t* fallbackList = (wchar_t*)xmalloc(bufferSize * sizeof(wchar_t));
    ULONG fallbackListSize;
    if (!GetUILanguageFallbackList(fallbackList, bufferSize, &fallbackListSize)) fatal_error("GetUILanguageFallbackList");
    if (fallbackListSize > bufferSize) {
        fallbackList = (wchar_t*)xrealloc(fallbackList, fallbackListSize * sizeof(wchar_t));
        if (!GetUILanguageFallbackList(fallbackList, fallbackListSize, &fallbackListSize)) fatal_error("GetUILanguageFallbackList");
    }
    char* utf8Str = ConvertUTF16ToUTF8(fallbackList);
    if (utf8Str == NULL) fatal("UTF-16 to UTF-8 conversion failed");
    printf("UI Language Fallback List: %s\n", utf8Str);
    free(fallbackList);
    free(utf8Str);
    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.