Mik*_*SFT 2 cmd exit-code errorlevel
编辑3
好的,所以看起来这可能不是安装程序问题.当我制作一个简单的批处理文件时:
exit /b 12
Run Code Online (Sandbox Code Playgroud)
并称之为
cmd /c test.cmd
echo %ERRORLEVEL%
Run Code Online (Sandbox Code Playgroud)
我在Windows Server 2003 R2上获得"12",在XP上获得"0".我以为我曾经多次测试过这个简单的测试用例,但显然没有.
所以,我已经更改了标签和标题,但是我在这里留下了其他信息,因为这里实际上有很多有用的东西与这个问题没有直接关系.
思考?
原来如下
我有一个用VBScript编写的自定义操作,而后者又调用Windows批处理文件(自定义操作基本上允许用户在安装时执行某些操作,以后也可以通过运行批处理文件来运行 - 这是一种方便).功能如下:
Function MainFunction
strCustomActionData = Session.Property("CustomActionData")
strSplit = Split(strCustomActionData, ";")
strInstallDir = strSplit(0)
strPostCopyAction = strSplit(1)
strScriptLocation = strInstallDir & "\MigrationMasterProcess.cmd"
strFullCommand = """" & strScriptLocation & """ " & strPostCopyAction
Set objShell = CreateObject("WScript.Shell")
Dim objExec
Set objExec = objShell.Exec(strFullCommand)
intReturnCode = objExec.ExitCode
Set objExec = Nothing
Set objShell = Nothing
WriteMessage "Return value: " & intReturnCode
' cf. http://msdn.microsoft.com/en-us/library/windows/desktop/aa371254(v=vs.85).aspx
If (intReturnCode = 0) Then
MainFunction = 1
Else
MainFunction = 3
End If
End Function
Run Code Online (Sandbox Code Playgroud)
当我在自定义操作之外运行相同类型的代码,并且批处理文件返回错误代码(通过EXIT/B)时,在intReturnCode中正确捕获返回值.但是,从自定义操作中,退出代码似乎"丢失" - 我总是返回0(我可以在WriteMessage调用的安装程序日志中看到这一点).如果我在shell上使用Exec或Run并不重要,我仍然会返回0.脚本在返回之前写出自己的返回码(我可以在Exec的stdout流中看到这个)所以我知道它不是实际上是0.我需要返回代码才能正确地将错误报告给安装程序.
想法?
对于记录,这是Windows XP SP3上的Windows Installer 3.0.安装程序是在Wise中,所以我没有WiX片段或者我会包含它,但这是被调用的函数.
这也有点剥离 - 我遗漏了对WriteMessage以及该函数的注释和其他调用.是的假 - 匈牙利人是邪恶的等等等等.
编辑:这是代码的C版本.它给出了同样的问题:
#include <Windows.h>
#include <msi.h>
#include <msiquery.h>
#include <stdio.h>
#include <stdlib.h>
#include "LaunchChildProcess.h"
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) {
return TRUE;
}
UINT __stdcall RunMigrationAction(MSIHANDLE hModule) {
UINT uiStat;
DWORD dwPropertySize = MAX_PATH * 2;
TCHAR szValueBuf[MAX_PATH * 2]; // arbitrary but we know the strings won't be near that long
TCHAR *szInstallDir, *szPostCopyAction;
TCHAR *szNextToken;
TCHAR szScriptLocation[MAX_PATH * 2];
TCHAR szParameters[MAX_PATH * 2];
INT iReturnValue;
LogTaggedString(hModule, TEXT("Action Status"), TEXT("Starting"));
uiStat = MsiGetProperty(hModule, TEXT("CustomActionData"), szValueBuf, &dwPropertySize);
if (ERROR_SUCCESS != uiStat) {
LogTaggedString(hModule, TEXT("Startup"), TEXT("Failed to get custom action data"));
return ERROR_INSTALL_FAILURE;
}
LogTaggedString(hModule, TEXT("Properties given"), szValueBuf);
LogTaggedInteger(hModule, TEXT("Property length"), dwPropertySize);
if (0 == dwPropertySize) {
return ERROR_INSTALL_FAILURE;
}
LogTaggedString(hModule, TEXT("Properties given"), szValueBuf);
szInstallDir = wcstok_s(szValueBuf, TEXT(";"), &szNextToken);
szPostCopyAction = wcstok_s(NULL, TEXT(";"), &szNextToken);
LogTaggedString(hModule, TEXT("Install dir"), szInstallDir);
LogTaggedString(hModule, TEXT("Post-copy action"), szPostCopyAction);
wcscpy_s(szScriptLocation, MAX_PATH * 2, szInstallDir);
wcscat_s(szScriptLocation, MAX_PATH * 2, TEXT("\\MigrationMasterProcess.cmd"));
LogTaggedString(hModule, TEXT("Script location"), szScriptLocation);
wcscpy_s(szParameters, MAX_PATH * 2, TEXT(" /C "));
wcscat_s(szParameters, MAX_PATH * 2, szScriptLocation);
wcscat_s(szParameters, MAX_PATH * 2, TEXT(" "));
wcscat_s(szParameters, MAX_PATH * 2, szPostCopyAction);
LogTaggedString(hModule, TEXT("Parameters to cmd.exe"), szParameters);
iReturnValue = ExecuteProcess(TEXT("cmd.exe"), szParameters);
LogTaggedInteger(hModule, TEXT("Return value from command"), iReturnValue);
LogTaggedString(hModule, TEXT("Action Status"), TEXT("Finished"));
return (0 == iReturnValue) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
}
void LogTaggedInteger(MSIHANDLE hInstall, TCHAR* szTag, INT iValue) {
TCHAR szValue[15];
_itow_s(iValue, szValue, 15, 10);
LogTaggedString(hInstall, szTag, szValue);
}
void LogTaggedString(MSIHANDLE hInstall, TCHAR* szTag, TCHAR* szMessage) {
MSIHANDLE hRecord;
UINT uiStat;
//TCHAR szFullMessage[4096];
//wcscpy_s(szFullMessage, 4096, TEXT("--------------- "));
//wcscat_s(szFullMessage, 4096, szTag);
//wcscat_s(szFullMessage, 4096, TEXT(": "));
//wcscat_s(szFullMessage, 4096, szMessage);
hRecord = MsiCreateRecord(3);
uiStat = MsiRecordSetString(hRecord, 0, TEXT("--------- [1]: [2]"));
uiStat = MsiRecordSetString(hRecord, 1, szTag);
uiStat = MsiRecordSetString(hRecord, 2, szMessage);
uiStat = MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_INFO), hRecord);
MsiCloseHandle(hRecord);
return;
}
int MsiMessageBox(MSIHANDLE hInstall, TCHAR* szString, DWORD dwDlgFlags) {
PMSIHANDLE newHandle = ::MsiCreateRecord(2);
MsiRecordSetString(newHandle, 0, szString);
return (MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_USER + dwDlgFlags), newHandle));
}
DWORD ExecuteProcess(TCHAR *szProcess, TCHAR *szParams) {
INT iMyCounter = 0, iPos = 0;
DWORD dwReturnVal = 0;
TCHAR *sTempStr = L"";
/* CreateProcessW can modify Parameters thus we allocate needed memory */
wchar_t * pwszParam = new wchar_t[wcslen(szParams) + 1];
if (NULL == pwszParam) {
return 1;
}
wcscpy_s(pwszParam, wcslen(szParams) + 1, szParams);
/* CreateProcess API initialization */
STARTUPINFOW siStartupInfo;
PROCESS_INFORMATION piProcessInfo;
memset(&siStartupInfo, 0, sizeof(siStartupInfo));
memset(&piProcessInfo, 0, sizeof(piProcessInfo));
siStartupInfo.cb = sizeof(siStartupInfo);
if (CreateProcessW(const_cast<LPCWSTR>(szProcess),
pwszParam, 0, 0, false,
CREATE_DEFAULT_ERROR_MODE, 0, 0,
&siStartupInfo, &piProcessInfo) != false) {
/* Watch the process. */
WaitForSingleObject(piProcessInfo.hProcess, INFINITE);
if (!GetExitCodeProcess(piProcessInfo.hProcess, &dwReturnVal)) {
dwReturnVal = GetLastError();
}
} else {
/* CreateProcess failed */
dwReturnVal = GetLastError();
}
/* Free memory */
free(pwszParam);
pwszParam = NULL;
/* Release handles */
CloseHandle(piProcessInfo.hProcess);
CloseHandle(piProcessInfo.hThread);
return dwReturnVal;
}
Run Code Online (Sandbox Code Playgroud)
在我的Windows Server 2003 R2 Visual Studio 2008框中运行时,我按预期获得错误代码:
--------- Return value from command: 5023
Run Code Online (Sandbox Code Playgroud)
在我的Windows XP测试框上运行时,我得到一个0,即使它应该是一个错误:
--------- Return value from command: 0
Run Code Online (Sandbox Code Playgroud)
两台机器都有Windows Installer 3.1.XP为3.01.4001.5512,2003 R2为3.01.4000.3959.
所以虽然我不知道是什么,但它们在盒子之间表现不同.
编辑2
由Wise for Windows Installer工具生成的操作的确切表行是:
"RunMigrationActionCA", "1537", "Calllaunchchildprocess", "RunMigrationAction", "0"
为了测试立即标志,我在类型列中添加了0x800,并且在最终行为中没有看到任何变化.
要清楚 - 这在2003 R2机器上工作正常.该机器没有加入域,但XP机器是.组策略中是否有任何可能导致此行为的内容?(此时抓住稻草.)
它似乎是WinXP的cmd.exe中的一个错误.
解决方案是使用exit 123而不是exit /b 123批处理文件.
如果您不想更改现有批处理文件,只需添加wrapper.bat:
@echo off
call %*
exit %errorlevel%
Run Code Online (Sandbox Code Playgroud)
并调用它:
system("wrapper.bat your.bat all your args")
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1759 次 |
| 最近记录: |