CMD,DevCon and Visual Fox Pro - windows

I made a .bat file using DevCon for restarting a device and when run it works.
When i try to run the same file in VFP form using the run command on click it says that DevCon is not recognized.
! cmd /c "C:\Windows\System32\restart.bat"
! "C:\Windows\System32\restart.bat"
I've tried making Sistem32 as a starting path and starting default and it does not work either way. It seems like CMD gets confused in the process. Thanks in advance for any help.

I would instead try using ShellExecute API. ie:
#Define SW_HIDE 0
#Define SW_NORMAL 1
#Define SW_SHOWMINIMIZED 2
#Define SW_SHOWMAXIMIZED 3
Local lcResult
lcResult = ShellExec('C:\Windows\System32\restart.bat', '', 'C:\Windows\System32', SW_NORMAL)
If !Empty(m.lcResult) && error
Messagebox(m.lcResult)
Endif
Function ShellExec
Lparameters tcExecutable,tcParams,tcWorkingDir,tnShowType,tcOperation
Declare Long ShellExecute In "shell32.dll" ;
long HWnd, String lpszOp, ;
string lpszFile, String lpszParams, ;
string lpszDir, Long nShowCmd
tcOperation = Iif(Empty(m.tcOperation), 'Open', m.tcOperation)
tcExecutable = Iif(Empty(m.tcExecutable), '', m.tcExecutable)
tcParams = Iif(Empty(m.tcParams), '', m.tcParams)
tcWorkingDir = Iif(Empty(m.tcWorkingDir), '', m.tcWorkingDir)
tnShowType = Iif(Type('m.tnShowType') # 'N', SW_SHOWNORMAL, m.tnShowType)
Local lnResult, lcError
lcError = ''
lnResult = ShellExecute(0,m.tcOperation,m.tcExecutable,m.tcParams,m.tcWorkingDir,m.tnShowType)
If !( m.lnResult > 32 ) && Error
lcError = GetShExecErrorMsg(m.lnResult)
Endif
Return m.lcError
Endfunc
Function GetShExecErrorMsg
Lparameters tnErrNum
Local Array aErrors[1]
Local lcMessage, lcErrors,lnErrors,ix
TEXT to m.lcErrors noshow
0,The operating system is out of memory or resources. \n
2,The specified file was not found. \n
3,The specified path was not found. \n
11,The .exe file is invalid (non-Win32® .exe or error in .exe image). \n
5,The operating system denied access to the specified file. \n
27,The file name association is incomplete or invalid. \n
30,The DDE transaction could not be completed because
other DDE transactions were being processed. \n
29,The DDE transaction failed. \n
28,The DDE transaction could not be completed because the request timed out. \n
32,The specified dynamic-link library was not found. \n
31,There is no application associated with the given file name extension.
This error will also be returned if you attempt to print a file that is not printable. \n
8,There was not enough memory to complete the operation. \n
26,A sharing violation occurred. \n
ENDTEXT
Clear
lnErrors = Alines(aErrors,m.lcErrors,.T.,'\n')
For ix=1 To m.lnErrors
If ( Val(Chrtran(Left(aErrors[m.ix],;
At(',',aErrors[m.ix])-1),Chr(13)+Chr(10),'')) = m.tnErrNum )
lcMessage = Substr(aErrors[m.ix],At(',',aErrors[m.ix])+1)
Exit
Endif
Endfor
If Empty(m.lcMessage)
lcMessage = 'An unspecified error occurred.'
Endif
Return m.lcMessage
Endfunc

Related

Prevent console window from being created in custom node.js build

I'm creating a custom build of node.js that should not show a console window to the user.
I've tried changing the linker config in the gyp file to 2 (which should set the linker flag /SUBSYSTEM:WINDOWS), but I still get a console window when I run the resulting node.exe binary.
How can I prevent the console window from appearing?
Edit: Further investigation reveals that the linker config in node.gyp is not taking effect. The generated node.vcxproj still has <Link><SubSystem>Console</SubSystem></Link> (which is very strange to me, since adding 'UACUIAccess': 'true' in the same part of node.gyp did take effect), so the built binary is incorrectly linked.
Solution 1
Save this one line of text as file invisible.vbs:
CreateObject(“Wscript.Shell”).Run “”"” & WScript.Arguments(0) & “”"”, 0, False
To run any program or batch file invisibly, use it like this:
wscript.exe “C:\Wherever\invisible.vbs” “C:\Some Other Place\MyBatchFile.bat”
To also be able to pass-on/relay a list of arguments use only two double quotes
CreateObject(“Wscript.Shell”).Run “” & WScript.Arguments(0) & “”, 0, False
eg: Invisible.vbs “Kill.vbs ME.exe”
Solution 2
Use a command line tool to silently launch a process : Quiet.
Solution 3
Roll your own C++ Win32 App:
PROCESS_INFORMATION procInfo = {0};
STARTUPINFOstartupInfo = {0};
SECURITY_ATTRIBUTESsaAttr = {0};
HANDLEhStdIn = GetStdHandle(STD_INPUT_HANDLE);
HANDLEhStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLEhStdErr = GetStdHandle(STD_ERROR_HANDLE);
// build up security attributes
saAttr.nLength = sizeof(saAttr);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// set file handles for process to be created
startupInfo.cb = sizeof(startupInfo);
startupInfo.dwFlags = STARTF_USESTDHANDLES;
startupInfo.hStdInput = hStdIn;
startupInfo.hStdOutput = hStdOut;
startupInfo.hStdError = hStdErr;
// build command line: format is [cmd.exe /c "%batchScript%" %batchArgs%]
if (-1 == _snprintf_s(cmd, sizeof(cmd),"cmd.exe /c \"%s\" %s", batchScript, batchArgs))
errorExit("_snprintf_s(\"cmd.exe /c \"%%s\" %%s\"), \"%s\", \"%s\") failed.", batchScript, batchArgs);
rc = CreateProcess(NULL, cmd, NULL, &saAttr, TRUE, CREATE_NO_WINDOW, NULL, tempPath, &startupInfo, &procInfo);
You have to change the SubSystem field value in node.exe PE optional header. The current value is 3 which is defined as Windows Console. If you change it to 2 (which is defined as Windows GUI) there would be no console window. In order to patch the executable file, you have to use utilities to change Optional Header of PE.
One example of such a tool is PE tools.
Click on Optinal Header and then change the Subsystem from 3 to 2.
That`s all.
Remember that with this change you can only run js files. You can not use interactive mode.
It appears that you must:
Comment out the 'SubSystem': 1 line in common.gypi. (Changing it to 2 causes the build to fail in mksnapshot.)
Change SubSystem to 2 in node.gyp
Also add 'EntryPointSymbol': 'wmainCRTStartup' to node.gyp.
This builds a node.exe that does not create a console window.

CreateProcess is able to execute batch files, but documentation says the opposite

Consider the following files:
a.bat:
#echo Hello from bat %1
and c.cpp:
#define UNICODE
#include <windows.h>
#include <stdio.h>
void check(TCHAR *cmd, TCHAR *args) {
STARTUPINFO sinf;
PROCESS_INFORMATION pinf;
memset(&sinf, 0, sizeof sinf);
sinf.cb = sizeof(sinf);
CreateProcess(cmd, args, NULL, NULL, FALSE, 0, NULL, NULL, &sinf, &pinf);
WaitForSingleObject(pinf.hProcess, INFINITE);
}
int main() {
TCHAR cmd1[] = L"a";
TCHAR cmd2[] = L"a.bat";
TCHAR cmdargs1[] = L"a argument";
TCHAR cmdargs2[] = L"a.bat argument";
TCHAR args[] = L"argument";
#define run_check(a, b) printf(#a " + " #b "\n"); fflush(stdout); check(a, b)
run_check(cmd1, cmdargs1);
run_check(cmd1, cmdargs2);
run_check(cmd1, args);
run_check(cmd2, cmdargs1);
run_check(cmd2, cmdargs2);
run_check(cmd2, args);
run_check(NULL, cmdargs1);
run_check(NULL, cmdargs2);
printf("Done\n");
return 0;
}
Note that I haven't specified cmd.exe in any of calls to CreateProcess, while MSDN says that I have to do it:
To run a batch file, you must start the command interpreter; set lpApplicationName to cmd.exe and set lpCommandLine to the following arguments: /c plus the name of the batch file.
However, I get the following output:
cmd1 + cmdargs1
cmd1 + cmdargs2
cmd1 + args
cmd2 + cmdargs1
Hello from bat argument
cmd2 + cmdargs2
Hello from bat argument
cmd2 + args
"argument" не является внутренней или внешней
командой, исполняемой программой или пакетным файлом.
NULL + cmdargs1
NULL + cmdargs2
Hello from bat argument
Done
This means that whenever .bat extension is explicitly specified either in lpApplicationName or lpCommandLine, batch file is successfully started. This works wit .cmd too, but not with .vbs. Does anyone know reason behind such behavior and difference between practice and documentation? Is such behavior 'an accident' or it persists among different Windows versions? (I use Windows 7 HP) Is there any point in documentation from which one can infer such behavior?
As a software developer, you shouldn’t rely on undocumented behavior. Even if something works fine when you test it, if the documentation says “you must do it another way”, you generally have to forget your tests, and do as instructed. Otherwise your software can silently break down with the next windows update, including even the minor update.
Now on the batch/vbs files.
To run the CMD/BAT, call GetEnvironmentVariable("ComSpec") to obtain path to cmd.exe, then call CreateProcess specifying command=cmd.exe, arguments /C path_to_CMD_file arg1 arg2.
If the path or arguments contain space, you must include them in quotes. If the path or arguments contain spaces contain ", replace with ^".
To run VBS, call ExpandEnvironmentStrings("%windir%\\System32\\cscript.exe") or wscript.exe, then pass VBS path in the first argument of the .exe file. If the path or an argument contain spaces or quotes, same rules apply to escaping.

OpenFile API returns error while opening file having name length above 127 characters

I am trying to open file which reside in a directory.
It is always return error code 13 if length is above or equal 127.
char name[200]="E:\\suri_temp\\abc85\\tool\\src1111\\turi_temp\\abc85\\tool\\src1111\\puri_temp\\abc85\\tool\\src\\nuri_temp\\abc85\\to\\abcd.tmp\\suri1111.log";
int len = strlen(name); //len=127
HFILE handle ;
WORD temp;
OFSTRUCT ofstruct;
if( (handle = OpenFile(name, &ofstruct, OF_EXIST)) == HFILE_ERROR )
{
temp = GetLastError(); // if length 127 or above(it comes here temp = 13)
}
else
_lclose(handle); // if length is below 127 it comes here
Anyone faced this problem?
You are just finding out the hard way what's well documented in the MSDN article for OpenFile:
Note This function has limited capabilities and is not recommended. For new application development, use the CreateFile function.
The OFSTRUCT structure contains a path string member with a length that is limited to OFS_MAXPATHNAME characters, which is 128 characters. Because of this, you cannot use the OpenFile function to open a file with a path length that exceeds 128 characters. The CreateFile function does not have this path length limitation.
As indicated, use CreateFile() instead.
Using
OpenFile(name, &ofstruct, OF_EXIST))
is ok in debug mode, but fails in release mode.
Use
if(GetFileAttributes("filename") == -1)

Windows fopen and the N flag

I'm reading some code that uses fopen to open files for writing. The code needs to be able to close and rename these files from time to time (it's a rotating file logger). The author says that for this to happen the child processes must not inherit these FILE handles. (On Windows, that is; on Unix it's OK.) So the author writes a special subroutine that duplicates the handle as non-inheritable and closes the original handle:
if (!(log->file = fopen(log->path, mode)))
return ERROR;
#ifdef _WIN32
sf = _fileno(log->file);
sh = (HANDLE)_get_osfhandle(sf);
if (!DuplicateHandle(GetCurrentProcess(), sh, GetCurrentProcess(),
&th, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
fclose(log->file);
return ERROR;
}
fclose(log->file);
flags = (*mode == 'a') ? _O_APPEND : 0;
tf = _open_osfhandle((intptr_t)th, _O_TEXT | flags);
if (!(log->file = _fdopen(tf, "at"))) {
_close(tf);
return ERROR;
}
#endif
Now, I'm also reading MSDN docs on fopen and see that their version of fopen has a Microsoft-specific flag that seems to do the same: the N flag:
N: Specifies that the file is not inherited by child processes.
Question: do I understand it correctly that I can get rid of that piece above and replace it (on Windows) with an additional N in the mode parameter?
Yes, you can.
fopen("myfile", "rbN") creates a non-inheritable file handle.
The N flag is not mentioned anywhere in Linux documentation for fopen, so the solution will be most probably not portable, but for MS VC it works fine.

How can I move files to the Recycle Bin in a Windows batch script or Perl?

I've got a Windows XP batch script which cleans some directories, but I would like to move the deleted files to trash instead of using plain del. How is this done?
It looks like the only languages I can use for this is plain batch or Perl.
use Win32::FileOp qw(Recycle);
Recycle(#ARGV);
Write a VBS script (Original Link) then call it with MyDelScript.vbs
function main()
{
if (WScript.Arguments.length != 1)
{
WScript.Echo("<Insert informative error message here>");
return;
}
var Path = WScript.Arguments(0);
var Shell = WScript.CreateObject("Shell.Application");
var Item = Shell.Namespace(0).ParseName(Path);
Item.InvokeVerb("delete");
}
The Win32::FileOp module has a Recycle function. From the docs:
Recycle #filenames
Send the files into the recycle bin. You will not get any confirmation dialogs.
Returns true if successful.
It can be done like this with plain batch and embedded VBScript. Put the following code into a file called recycle.cmd:
<!-- : Begin batch script
#echo off
if "%1"=="" (
echo Usage: %~nx0 FILE_TO_RECYCLE[...]
echo This script puts files into the recycle bin
exit /b 1
)
cscript //nologo "%~f0?.wsf" %*
exit /b %errorlevel%
----- Begin embedded wsf script --->
<job><script language="VBScript">
Set app = WScript.CreateObject("Shell.Application")
Set fso = CreateObject("Scripting.FileSystemObject")
For Each arg In WScript.Arguments
If fso.FileExists(arg) Then
Set file = fso.GetFile(arg)
Set folderItem = app.Namespace(0).ParseName(file.Path)
folderItem.InvokeVerb("delete")
Else
WScript.Echo "File not found: " & arg
End If
Next
</script></job>
Example:
echo This file is dirt.> dirt.txt
echo This file is trash.> trash.txt
recycle dirt.txt trash.txt
As you can see the script allows recycling multiple files with one command.
It does not suppport the wildcards * and ? though.
The idea of embedding VBScript inside a batch file is taken from dbenham's answer to Is it possible to embed and execute VBScript within a batch file without using a temporary file? (scroll down to UPDATE 2014-04-27).
You could use the "recycle" utility which is part of CmdUtils from MaDdoG Software. From the page listing -
Recycle, a safe replacement for the DEL command, that sends files to the recycle bin instead of deleting them. Recycle is also more flexible than DEL; you can specify multiple files at once (or use wildcards), and you can recycle whole directories at once (be careful!)
I would suggest you try its various switches before you incorporate it into your script - there is quite a bit of deviation from the default behaviour of the "del" command.
UPDATE: Contrary to my original claim that the following code does not work, it indeed seems to work. I just forgot that the file I wanted to delete was not in $ENV{TEMP} but a subdirectory of $ENV{TEMP}. The problem is, the file does not go to the Recycle Bin.
The right solution is to use Win32::FileOp but I am going to leave this script here as an example of how to use Win32::API and Win32::API::Struct. I would appreciate it if anyone can point out what I am doing wrong. For your reference:
SHFileOperation: http://msdn.microsoft.com/en-us/library/bb762164(VS.85).aspx
LPSHFILEOPSTRUCT: http://msdn.microsoft.com/en-us/library/bb759795(VS.85).aspx
#!/usr/bin/perl
use strict;
use warnings;
use File::Spec::Functions qw( catfile );
use Win32::API;
Win32::API::Struct->typedef(
SHFILEOPSTRUCT => qw(
HWND hwnd;
UINT wFunc;
LPCTSTR pFrom;
LPCTSTR pTo;
FILEOP_FLAGS fFlags;
BOOL fAnyOperationsAborted;
LPVOID hNameMappings;
LPCTSTR lpszProgressTitle;
)
);
Win32::API->Import(
shell32 => q{ int SHFileOperation( LPSHFILEOPSTRUCT lpFileOp ) }
);
my $op = Win32::API::Struct->new( 'SHFILEOPSTRUCT' );
$op->{wFunc} = 0x0003; # FO_DELETE from ShellAPI.h
$op->{fFlags} = 0x0040; # FOF_ALLOWUNDO from ShellAPI.h
my $to_delete = catfile( $ENV{TEMP}, "test.file" );
$op->{pFrom} = $to_delete . "\0\0";
my $result = SHFileOperation( $op );
if ( $result ) {
warn sprintf "The operation failed: %4.4X\n", $result;
}
else {
if ( $op->{fAnyOperationsAborted} ) {
warn "Operation was aborted\n";
}
else {
warn "The operation succeeded\n";
}
}
__END__

Resources