GetLastError在SystemParametersInfo中返回错误2

GetLastError returns error 2 in SystemParametersInfo

本文关键字:错误 返回 SystemParametersInfo GetLastError      更新时间:2023-10-16
#include <iostream>
#include <windows.h>
using namespace std;
int main(){
    LPWSTR test = L"c:/aizen.png";
    int result = SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, test, SPIF_UPDATEINIFILE);
    if(result)
        cout << "Wallpaper set!";
    else
        cout << "Error: " << GetLastError();
    cin >> result;
    return 0;
}

该代码只是为了更改背景壁纸,但我一直收到错误:2,意思是"找不到文件"。但是,文件就在那里!我使用的是微软visual studio 2010,我尝试过以管理员身份运行,区分大小写,更改斜杠等。我做错了什么?

错误2为File not found

首先,确保aizen.png实际上位于驱动器C:的根文件夹中(在Vista及更高版本上,这是不可能的,因为非管理员用户通常没有写访问权限(。

如果文件确实存在,那么问题很可能是您没有正确转义反斜杠:

LPWSTR test = L"c:\aizen.png";

问题是将UNICODE字符串LPWSTR-传递给采用ANSI的API。

几乎所有的Win32 API(所有这些API都接受字符串(都有两个版本,一个以…结尾。。。一个表示ANSI(8位字符(,一个以…结尾。。。W代表Wide char,也就是UNICODE(从技术上讲不是"真正的"UNICODE,但这比在这个回复中得到的更值得(。

如果您在编译时有UNICODE #define d,那么纯素版本将被#定义为。。。W版本;否则它被#定义为。。。一个版本。看看winuer.h,你会看到:

WINUSERAPI
BOOL
WINAPI
SystemParametersInfoA(
    __in UINT uiAction,
    __in UINT uiParam,
    __inout_opt PVOID pvParam,
    __in UINT fWinIni);
WINUSERAPI
BOOL
WINAPI
SystemParametersInfoW(
    __in UINT uiAction,
    __in UINT uiParam,
    __inout_opt PVOID pvParam,
    __in UINT fWinIni);
#ifdef UNICODE
#define SystemParametersInfo  SystemParametersInfoW
#else
#define SystemParametersInfo  SystemParametersInfoA
#endif // !UNICODE

请注意,Windows具有两个SystemParametersInfo函数;W期望宽的LPWSTR,而A期望普通的LPSTR;以及是否定义了UNICODE,选择哪个是"默认"UNICODE。(您总是可以手动添加A或W来显式调用。(

在您的原始代码中可能发生的情况是,因为您没有定义UNICODE,所以最终使用。。。一个版本,它需要一个ANSI字符串,但您传递的是UNICODE字符串,所以它不起作用。

您为使其工作所做的"一点更改"不仅仅是一点:您现在正在将ANSI字符串传递给。。。API的一个版本,所以它工作得很好:

int result = SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (void*)"c:/aizen.jpg", SPIF_UPDATEINIFILE);

或者,您可以使用LPWSTR:显式调用W版本

int result = SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, L"c:\aizen.jpg", SPIF_UPDATEINIFILE);

或者,你可以在应用程序开始时定义UNICODE,使用L"…"字符串和API的普通版本——只需在#include之前在原始应用程序的顶部添加#define UNICODE。(UNICODE通常是在生成文件或编译器设置选项中定义的,而不是在代码中明确定义的,所以如果你是Win32编程的新手,它可能会成为一个令人惊讶的功能。(

请注意,LPWSTR是而不是已弃用;如果说有什么不同的话,那就是相反;自XP以来,Win32的典型做法是全面使用W风格的字符串,因此它实际上是Win32上被认为"不推荐"的普通"…"字符串。(例如,许多COM API只使用宽字符串。(

大多数其他功能对此有一定的保护作用;如果您不小心试图传递一个ANSI字符串,比如SetWindowTextW,您将得到一个编译时错误,因为您传递的LPSTR与函数期望的已导出LPWSTR类型不匹配。但SystemParamtersInfo很棘手;它为数据参数取了一个void*,因此在编译时会接受[most]任何,只有当您在运行时调用该函数时才会出现错误。

--

顺便说一句,这是David Herfernan在你第一次发布时对你的问题的回答中指出的

脑海中浮现出一些可能的原因:

  • 您的ANSI/Unicode编码不匹配

这看起来很奇怪,如果你用MinGW c++编译器编译,它实际上会进行一些更改:

int main(){
        int result = SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (void*)"c:/aizen.jpg", SPIF_UPDATEINIFILE);

这是可行的,显然LPWSTR已被弃用。。。Visual Studio可能存在权限问题。以管理员身份运行它,然后重试。