如何使用 UnicodeStrings 正确调用 GetModuleFileName

How to make a correct call to GetModuleFileName with UnicodeStrings

GetModuleFileName 未返回 Windows 服务的程序文件名。

我已经将变量定义为 AnsiString 和 UnicodeString,但似乎与我用来获取此值的事件处理程序有关。

AnsiString exefile = "", sIniFile = "", AppFile = "";

DWORD tamanho = MAX_PATH;
LPTSTR lpBuffer = exefile.c_str();

this->LogMessage("Iniciando serviço",EVENTLOG_INFORMATION_TYPE,0,0);

tamanho = GetModuleFileName( NULL, lpBuffer, tamanho );
if( tamanho > 0 ){ // retornou nome !
   exefile = String(lpBuffer);
}
else
{
     this->LogMessage("Impossível determinar pasta do  executável",EVENTLOG_ERROR_TYPE,0,0);
     Started = false;
     return;
 }

 sIniFile = ChangeFileExt( exefile, L".ini");
 if( !FileExists(sIniFile) )
 {
    this->LogMessage("Arquivo de inicialização não   encontrado",EVENTLOG_ERROR_TYPE,0,0);
    Started = false;
    return;
 }
 else
      this->LogMessage(sIniFile,EVENTLOG_INFORMATION_TYPE,0,0);
 /*
 // Debug
 Started = true;
 return;
 */

没有任何错误信息。应用程序编译成功,但在应用程序路径中没有找到实际存在的初始化文件。

我在另一个服务应用程序上使用了相同的代码,并且运行良好。

请问我做错了什么?

是否有任何教程显示处理 UnicodeString 的示例?

您在滥用 GetModuleFileName()

您没有将 分配的 缓冲区传递给 GetModuleFileName(),因此它无处可存储其输出。字符串的 c_str() 方法永远不会 returns NULL 指针,因此如果字符串为空,c_str() returns 指向存储在静态内存中的空字符的指针。你告诉 GetModuleFileName() 你已经为你给它的缓冲区分配了内存,但你真的没有,所以当 GetModuleFileName() 试图写入你的 non-allocated 缓冲区时,它要么垃圾内存,或者直接崩溃。

改用更像这样的东西:

this->LogMessage(_D("Iniciando serviço"), EVENTLOG_INFORMATION_TYPE, 0, 0);

WCHAR szBuffer[MAX_PATH];
DWORD tamanho = GetModuleFileNameW(NULL, szBuffer, MAX_PATH);

if( tamanho == 0 ){ // retornou nome !
{
    this->LogMessage(_D("Impossível determinar pasta do  executável"), EVENTLOG_ERROR_TYPE, 0, 0);
    Started = false;
    return;
}

String exefile(szBuffer, tamanho);

String sIniFile = ChangeFileExt(exefile, _D(".ini"));
if (!FileExists(sIniFile))
{
    this->LogMessage(_D("Arquivo de inicialização não encontrado"), EVENTLOG_ERROR_TYPE, 0, 0);
    Started = false;
    return;
}

this->LogMessage(sIniFile, EVENTLOG_INFORMATION_TYPE, 0, 0);

/*
// Debug
Started = true;
return;
*/

或者,您可以这样做:

this->LogMessage(_D("Iniciando serviço"), EVENTLOG_INFORMATION_TYPE, 0, 0);

UnicodeString exefile;
exefile.SetLength(MAX_PATH);

DWORD tamanho = GetModuleFileNameW(NULL, &exefile[1], MAX_PATH);

if( tamanho == 0 ){ // retornou nome !
{
    this->LogMessage(_D("Impossível determinar pasta do  executável"), EVENTLOG_ERROR_TYPE, 0, 0);
    Started = false;
    return;
}

exefile.SetLength(tamanho);

String sIniFile = ChangeFileExt(exefile, _D(".ini"));
if (!FileExists(sIniFile))
{
    this->LogMessage(_D("Arquivo de inicialização não encontrado"), EVENTLOG_ERROR_TYPE, 0, 0);
    Started = false;
    return;
}

this->LogMessage(sIniFile, EVENTLOG_INFORMATION_TYPE, 0, 0);

/*
// Debug
Started = true;
return;
*/

也就是说,您实际上根本不需要直接调用 GetModuleFileName()。您可以改用 RTL 的 ParamStr() 1 函数。当它的Index参数为0时,它returns调用进程的路径和文件名(即它在内部为你调用GetModuleFileName()),如:

this->LogMessage(_D("Iniciando serviço"), EVENTLOG_INFORMATION_TYPE, 0, 0);

String exefile = ParamStr(0);

String sIniFile = ChangeFileExt(exefile, _D(".ini"));
if (!FileExists(sIniFile))
{
    this->LogMessage(_D("Arquivo de inicialização não encontrado"), EVENTLOG_ERROR_TYPE, 0, 0);
    Started = false;
    return;
}

this->LogMessage(sIniFile, EVENTLOG_INFORMATION_TYPE, 0, 0);

/*
// Debug
Started = true;
return;
*/

1:在 VCL Forms 应用程序中,Application->ExeName 属性 只是 returns ParamStr(0).