GetModuleFileName函数第2个参数是LPWSTR 类型,结果读出来的路径中间总有一个0

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GetModuleFileName函数第2个参数是LPWSTR 类型,结果读出来的路径中间总有一个0相关的知识,希望对你有一定的参考价值。

GetModuleFileName函数第2个参数是LPWSTR 类型,结果读出来的路径中间总有一个0,结果也得不到正确路径。怀疑是LPWSTR 类型所致。转成char型又报错。该怎么弄呢?

  确切说,GetModuleFileName的定义是一个宏,在UNICODE版本下,GetModuleFileName等同于GetModuleFileNameW,在ANSI版本下等同于GetModuleFileNameA。

  GetModuleFileNameA和GetModuleFileNameW的区别在于它们的字符串参数的“字符宽度”,这两个函数的原型如下:

DWORD WINAPI GetModuleFileNameA( HMODULE hModule, 
LPSTR
 lpFilename, DWORD nSize );//ANSI版本,第二个参数是LPSTR,也就是char*。这意味着你需要向其传递的参数是char类型的字符串

DWORD WINAPI GetModuleFileNameW( HMODULE hModule, 
LPWSTR
 lpFilename, DWORD nSize );//UNICODE版本,第二个参数是LPWSTR,也就是wchar_t*。这意味着你需要向其传递的参数是wchar_t类型的字符串。

  如果你的代码预定义了宏“UNICODE”,那么在编译时,“GetModuleFileName”就会被替换成“GetModuleFileNameW”,否则就是“GetModuleFileNameA”。

  同理,_tcsrchr也是一个宏,当预定义了“_UNICODE”宏时,它会在编译时替换为

wchar_t *wcsrchr(
   const wchar_t *str,
   wchar_t c 
); // C only


  因为凡是涉及字符串的函数,几乎都有对应的ANSI和UNICODE版本,比如wcsrchr、strrchr、strcmp、wcscmp等等。在你的代码中对各个接口、函数的ANSI版本和UNICODE版本的使用应该始终保持一致,以避免出现错误。

  而你的代码,首先明确使用了ANSI版本的接口GetModuleFileNameA,而其后又将ANSI字符串提交给UNICODE版本的wcsrchr使用,所以会出现错误。


  另:关于char和wchar_t的区别想必你应该了解,wchar_t字符串中每一个字符都由两个字节组成,对于ascii表中的字符,都会在高位字节补0以补齐两个字节。字符a其ascii码为0x61,用char类型表示时其值为0x61,但是用wchar_t表示时,由于wchar_t为双字符,因此其值应是0x0061——在INTEL x86和x64架构的系统中,字节序列表示就成了“0x61 0x00”。

  比如有字符串"abcdefg",当你用char类型表示这一串字符串时,C代码会这样写:

char aString[] = "abcdefg";

  它在内存中的存在形式将是这样的:

  61 62 63 64 65 66 67 00                         ; abcdefg.

  如果用wchar_t去表示,C代码如下:

wchar_t wString[] = L"abcdefg";

  在内存中的存在形式就会变为这样:

  61 00 62 00 63 00 64 00 65 00 66 00 67 00 00 00 ; a.b.c.d.e.f.g...

  由于每个字符都要双字符表示,因此在此示例中wchar_t表示的字符串会多了一半的0。当你把wchar_t表示的字符串字节序列强行当作char*类型来处理时,就会出现意料之外的问题。


  因此你的代码应该这样写:

TCHAR tszCfgFile[MAX_PATH]=0;//TCHAR也是宏定义,当预定义了UNICODE时,等同于wchar_t,否则等于char。与GetModuleFileName的宏定义保持一致。
GetModuleFileName( gDllModule, tszCfgFile, MAX_PATH); 
_tcsrchr( tszCfgFile, _T('\\\\') )[1] = 0;//这样写是危险的,如果tszCfgFile并不包含\\\\,此行将导致崩溃。

  

参考技术A Private Declare Function GetModuleFileName Lib "kernel32" Alias "GetModuleFileNameA" (Byval hModule As Long,Byval lpFileName As String,Byval nSize As Long) As Long

Private Sub Command1_Click()
Dim StrFileName As String * 128
GetModuleFileName 0,StrFileName,128
MsgBox StrFileName
End Sub追问

GetModuleFileNameA用这个函数后,紧接着_tcsrchr函数要转回LPWSTR,就退出了。
如下两行代码,不能共存啊。
GetModuleFileNameA(gDllModule, (LPSTR)sCfgFile, MAX_PATH);
(_tcsrchr((LPWSTR)sCfgFile, _T('\\')))[1] = 0;

追答

你这不是VB啊,怎么问到VB板块来了

Windows API一日一练 83 GetModuleFileName函数

在开发软件的过程里,经常需要把数据保存到当前执行文件路径下面,或者读取当前执行文件路径下的一些配置信息。这时就需要从当前模块里获取所在的目录路径,以便进行固定的位置操作文件。要解决这个需求,就需要调用API函数GetModuleFileName来获取模块所在的路径。
 
函数GetModuleFileName声明如下:
WINBASEAPI
DWORD
WINAPI
GetModuleFileNameA(
    __in_opt HMODULE hModule,
    __out_ecount_part(nSize, return + 1) LPCH lpFilename,
    __in     DWORD nSize
    );
WINBASEAPI
DWORD
WINAPI
GetModuleFileNameW(
    __in_opt HMODULE hModule,
    __out_ecount_part(nSize, return + 1) LPWCH lpFilename,
    __in     DWORD nSize
    );
#ifdef UNICODE
#define GetModuleFileName GetModuleFileNameW
#else
#define GetModuleFileName GetModuleFileNameA
#endif // !UNICODE
hModule是模块的句柄,或者设置为NULL表示当前模块。
lpFilename是保存路径的缓冲区。
nSize是缓冲区的大小。
 
调用函数的例子如下:
#001 //获取当前程序所在路径。
#002  //蔡军生 2007/12/05 QQ:9073204 深圳
#003  void TestGetExePath(void)
#004  {
#005         //
#006         const int nBufSize = 512;
#007         TCHAR chBuf[nBufSize];
#008         ZeroMemory(chBuf,nBufSize);
#009 
#010         //获取当前执行文件的路径。
#011        if (GetModuleFileName(NULL,chBuf,nBufSize))
#012         {
#013               //输出带文件名称路径。
#014               OutputDebugString(chBuf);
#015               OutputDebugString(_T("/r/n"));
#016 
#017               //获取文件路径。
#018               TCHAR* lpStrPath = chBuf;
#019               PathRemoveFileSpec(lpStrPath);
#020               OutputDebugString(lpStrPath);
#021               OutputDebugString(_T("/r/n"));
#022         }
#023 
#024  }
 
输出的结果如下:
g:/work/windows_api/wincpp2/debug/WinCpp.exe
g:/work/windows_api/wincpp2/debug
 
 

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

以上是关于GetModuleFileName函数第2个参数是LPWSTR 类型,结果读出来的路径中间总有一个0的主要内容,如果未能解决你的问题,请参考以下文章

Windows API一日一练 83 GetModuleFileName函数

c语言程序如何设置默认路径

LPWSTR和char*是啥关系,这段代码求解决问题

PathRemoveFileSpec 函数的作用:将路径末尾的文件名和反斜杠去掉(与GetModuleFileName配合)

第二个参数是获取shell脚本函数中第一个参数的内容[重复]

EXCEL函数中OFFSET表达的是啥意思