-2

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;
 */

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

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

请问我做错了什么?

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

4

1 回答 1

1

你在滥用GetModuleFileName().

您没有将分配的缓冲区传递给GetModuleFileName(),因此它无处存储其输出。字符串的c_str()方法从不返回 NULL 指针,因此如果字符串为空,则c_str()返回指向存储在静态内存中的空字符的指针。你说GetModuleFileName()你已经为你给它的缓冲区分配了内存,但你真的没有,所以当GetModuleFileName()你尝试写入你的未分配缓冲区时,它要么会浪费内存,要么会直接崩溃。

改用类似这样的东西:

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 的1函数。当它的参数为0时,它返回调用进程的路径和文件名(即它在内部为你调用),例如:ParamStr() IndexGetModuleFileName()

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 表单应用程序中,该Application->ExeName属性仅返回ParamStr(0).

于 2019-05-22T23:26:12.427 回答