Page 1 of 1

проблема запуска cmd /c

Posted: Tue 12 Mar, 2019 07:12
by ionic
Столкнулся с еще одной проблемой - мне надо выполнить команду интерпретатора cmd и дождаться ее выполнения.
win.ShellExecute не дает такой возможности, только ShellExecuteEx из WinAPI.
os.Execute использовать не могу, т.к. в панелях открыт NetBox и он попытается выполнить это в данной панели, там вообще баш.

Возможно ли как-то использовать ShellExecuteEx в lua скрипте, или как-то по другому исполнить cmd /c command и дождаться его выполнения именно на хосте ФАРа, а не на хосте того, что открыто в панели?

Бог ты мой, нашел на задворках форума и переделал, может кому нужно будет:

Code: Select all

function MsgBox( msg )
	far.Message( msg )
end

local ffi = require "ffi"
local C = ffi.C
ffi.cdef [[
	typedef struct { // _SECURITY_ATTRIBUTES
		unsigned long nLength;
		void* lpSecurityDescriptor;
		int32_t bInheritHandle;
	} SECURITY_ATTRIBUTES;
	 
	typedef struct { // _STARTUPINFOW
		unsigned long cb;
		wchar_t* lpReserved;
		wchar_t* lpDesktop;
		wchar_t* lpTitle;
		unsigned long dwX;
		unsigned long dwY;
		unsigned long dwXSize;
		unsigned long dwYSize;
		unsigned long dwXCountChars;
		unsigned long dwYCountChars;
		unsigned long dwFillAttribute;
		unsigned long dwFlags;
		unsigned short wShowWindow;
		unsigned short cbReserved2;
		unsigned char* lpReserved2;
		void* hStdInput;
		void* hStdOutput;
		void* hStdError;
	} STARTUPINFOW;
 
	typedef struct { // _PROCESS_INFORMATION
		void* hProcess;
		void* hThread;
		unsigned long dwProcessId;
		unsigned long dwThreadId;
	} PROCESS_INFORMATION;
 
	int32_t CreatePipe(void** hReadPipe,void** hWritePipe,SECURITY_ATTRIBUTES* lpPipeAttributes,unsigned long nSize);
	int32_t CreateProcessW(const wchar_t* lpApplicationName,wchar_t* lpCommandLine,SECURITY_ATTRIBUTES* lpProcessAttributes,SECURITY_ATTRIBUTES* lpThreadAttributes,int32_t bInheritHandles,unsigned long dwCreationFlags,void* lpEnvironment,const wchar_t* lpCurrentDirectory,STARTUPINFOW* lpStartupInfo,PROCESS_INFORMATION* lpProcessInformation); // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
	int32_t ReadFile(void* hFile,void* lpBuffer,unsigned long nNumberOfBytesToRead,unsigned long* lpNumberOfBytesRead,void* lpOverlapped);
	int32_t CloseHandle(void* hObject);
	void* GetStdHandle(unsigned long nStdHandle);
	int32_t GetLastError(void);
	bool GetExitCodeProcess(HANDLE hProcess, int32_t* lpExitCode); // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683189(v=vs.85).aspx
	int32_t WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds); // https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx
 
	int32_t IsTextUnicode(const void* lpv,int iSize,int* lpiResult);
]]
local advapi32 = ffi.load("advapi32")
local IS_TEXT_UNICODE_ASCII16 = 0x0001
local IS_TEXT_UNICODE_STATISTICS = 0x0002
local STILL_ACTIVE = 0x0103 -- = 259 = STATUS_PENDING in WinNT.h
 
local CREATE_NO_WINDOW = 0x8000000
local STD_INPUT_HANDLE = -10
local STARTF_USESTDHANDLES = 0x00000100
local INFINITE = 0xFFFFFFFF
	 
local function exec( command )
	local exitcode = ffi.new( "DWORD[1]" )
	local ret, err, output = nil

	local pipe_security = ffi.new( "SECURITY_ATTRIBUTES" )
	pipe_security.nLength = ffi.sizeof( pipe_security )
	pipe_security.bInheritHandle = true
	local pipe_in,pipe_out = ffi.new( "void*[1]" ), ffi.new( "void*[1]" )
	if C.CreatePipe( pipe_in, pipe_out, pipe_security, 0 ) then
		local startup = ffi.new( "STARTUPINFOW" )
		startup.cb = ffi.sizeof( startup )
		startup.dwFlags = STARTF_USESTDHANDLES
		startup.hStdInput = C.GetStdHandle( STD_INPUT_HANDLE )
		startup.hStdOutput = pipe_out[0];
		startup.hStdError = pipe_out[0];
		local info = ffi.new( "PROCESS_INFORMATION" )

		if C.CreateProcessW(
			ffi.NULL,
			command and ffi.cast( "void*", win.Utf8ToUtf16( command .. "\0" ) ) or ffi.NULL,
			ffi.NULL,
			ffi.NULL,
			true,
			CREATE_NO_WINDOW,
			ffi.NULL,
			folder and ffi.cast( "void*", win.Utf8ToUtf16( folder .. "\0" ) ) or ffi.NULL,
			startup,
			info ) ~= 0 then
				C.CloseHandle( pipe_out[0] )

				local size = 1024
				local buffer = ffi.new( "char[?]", size )
				local readed = ffi.new( "unsigned long[1]" )
				local unicode = ffi.new( "int[1]" )
				unicode[0] = bit64.bor( IS_TEXT_UNICODE_ASCII16, IS_TEXT_UNICODE_STATISTICS )

				output = ""
				while true do
					C.ReadFile( pipe_in[0], buffer, size, readed, ffi.NULL )
					if readed[0] == 0 then
						break
					else
						output = output .. ( advapi32.IsTextUnicode( buffer, readed[0], unicode ) == 0 and win.OemToUtf8 or win.Utf16ToUtf8 )( ffi.string( buffer, readed[0] ) )
					end
				end

				--C.WaitForSingleObject(info.hProcess,INFINITE)
				if C.GetExitCodeProcess( info.hProcess, exitcode ) then
					ret = exitcode[0]
					err = nil
				else
					ret = false
					err = C.GetLastError()
				end

				C.CloseHandle( info.hThread )
				C.CloseHandle( info.hProcess )
		else
			ret = nil
			err = C.GetLastError()
		end

		C.CloseHandle( pipe_in[0] )
	end

	return ret, err, output
end

ret, err, output = exec( "cmd /c \"dir *.*\"" )

проблема запуска cmd /c

Posted: Tue 12 Mar, 2019 12:50
by John Doe
ionic wrote: Tue 12 Mar, 2019 07:12 os.Execute использовать не могу, т.к. в панелях открыт NetBox и он попытается выполнить это в данной панели
Не попытается.
win.system проще всего.

проблема запуска cmd /c

Posted: Tue 19 Mar, 2019 08:08
by ionic
Спасибо за ответ.

Ну при os.execute когда у открыт NetBox в панели в котором открыт linux-сервер - приходят ошибки от bash - что логично, т.к. команды то для виндового cmd.

А вот про win.system да, попробую.