I have a Visual Studio 2008 C++03 project using Lua 5.2.1 where I would like to allow a Lua script to use Win32 iteration functions (FindFirst*, FindNext*, etc...)
For example, I'd like to be able to list the running processes:
#include <tlhelp32.h>
#pragma comment( lib, "toolhelp.lib" )
static int process_iter_next( lua_State* L )
{
HANDLE h = *( HANDLE* )lua_touserdata( L, lua_upvalueindex( 1 ) );
PROCESSENTRY32 pe;
pe.dwSize = sizeof( PROCESSENTRY32 );
if( ::Process32Next( h, &pe ) )
{
lua_pushstring( L, pe.szExeFile );
return 1;
}
return 0;
}
static int process_iter_first( lua_State* L )
{
HANDLE h = *( HANDLE* )lua_touserdata( L, lua_upvalueindex( 1 ) );
PROCESSENTRY32 pe;
pe.dwSize = sizeof( PROCESSENTRY32 );
if( ::Process32First( h, &pe ) )
{
lua_pushstring( L, pe.szExeFile );
// How do I replace the closure with process_iter_next?
return 1;
}
return 0;
}
static int l_list( lua_State *L )
{
HANDLE* h = ( HANDLE* )lua_newuserdata( L, sizeof( HANDLE ) );
luaL_getmetatable( L, "process.list" );
lua_setmetatable( L, -2 );
*h = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0 );
if( INVALID_HANDLE_VALUE == *h )
luaL_error( L, "Failed to list processes. EC: %d", ::GetLastError() );
lua_pushcclosure( L, process_iter_first, 1 );
return 1;
}
static int process_gc( lua_State* L )
{
HANDLE h = *( HANDLE* )lua_touserdata( L, 1 );
if( INVALID_HANDLE_VALUE != h )
::CloseToolhelp32Snapshot( h );
return 0;
}
extern "C" int luaopen_process( lua_State *L )
{
static const luaL_Reg process[] = {
{ "list", l_list },
{ NULL, NULL }
};
luaL_newmetatable( L, "process.list" );
lua_pushstring( L, "__gc" );
lua_pushcfunction( L, process_gc );
lua_settable( L, -3 );
luaL_newlib( L, process );
return 1;
}
My Lua script:
for p in process.list() do
print(p)
end
When I run this, only the process_iter_first will be called. How do I replace the c-closure created in l_list with process_iter_next when Process32First succeeds?
EDIT per #Mud's suggestion*
static int process_iter( lua_State* L )
{
HANDLE h = *( HANDLE* )lua_touserdata( L, lua_upvalueindex( 1 ) );
typedef BOOL ( *PFN_ProcessIter )( HANDLE, LPPROCESSENTRY32 );
PFN_ProcessIter next = ( PFN_ProcessIter )lua_touserdata( L, lua_upvalueindex( 2 ) );
PROCESSENTRY32 pe;
pe.dwSize = sizeof( PROCESSENTRY32 );
if( next( h, &pe ) )
{
lua_pushstring( L, pe.szExeFile );
lua_pushlightuserdata( L, Process32Next );
// not sure how to use this function. The docs are not enlightening.
// lua_setupvalue( L, ???, ??? );
// This looked like a good idea from the docs, but it causes an access violation
// lua_setuservalue( L, lua_upvalueindex( 2 ) );
return 1;
}
return 0;
}
static int l_list( lua_State *L )
{
HANDLE* h = ( HANDLE* )lua_newuserdata( L, sizeof( HANDLE ) );
luaL_getmetatable( L, "process.list" );
lua_setmetatable( L, -2 );
*h = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0 );
if( INVALID_HANDLE_VALUE == *h )
luaL_error( L, "Failed to list processes. EC: %d", ::GetLastError() );
lua_pushlightuserdata( L, Process32First );
lua_pushcclosure( L, process_iter, 2 );
return 1;
}
Just push the address of the function to call as another upvalue of your closure (lua_pushlightuserdata) then update it on the first call.
Or change your userdata to a structure which contains a handle and the function pointer, and update the function pointer on your first call.
Response to PaulH's edit:
static int process_iter( lua_State* L )
{
HANDLE h = *( HANDLE* )lua_touserdata( L, lua_upvalueindex( 1 ) );
typedef BOOL (WINAPI *PFN_ProcessIter )( HANDLE, LPPROCESSENTRY32 );
PFN_ProcessIter next = ( PFN_ProcessIter )lua_touserdata( L, lua_upvalueindex( 2 ) );
PROCESSENTRY32 pe;
pe.dwSize = sizeof( PROCESSENTRY32 );
if( next( h, &pe ) )
{
lua_pushstring( L, pe.szExeFile );
if (next == Process32First)
{
lua_pushlightuserdata(L, Process32Next);
lua_replace(L, lua_upvalueindex(2));
}
return 1;
}
return 0;
}
Related
I tried copying this example: https://docs.oracle.com/cd/E19957-01/817-6707/search.html
I am trying to get the DN to bind to a user. But when searching ldap_result always says that the server is busy. Is there something else I need to do to get this to work?
LDAP *ld = NULL;
int iDebug = session.ini["ldap_debug_level"].Int32();
string sHostIP = session.ini["ldap_host"];
string sPort = session.ini["ldap_port"];
string sURL = sHostIP+":"+sPort;
int iErr;
iErr = ldap_initialize( &ld, sURL.c_str() );
if( iErr != LDAP_SUCCESS )
{
ldap_unbind(ld);
return false;
}
int iVersion = LDAP_VERSION3;
if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &iVersion ) != LDAP_OPT_SUCCESS )
{
ldap_unbind(ld);
return false;
}
string sLDAPPW = session.ini["ldap_server_pw"];
struct berval pServerPassword = { 0, NULL };
pServerPassword.bv_val = ber_strdup( &sLDAPPW[0] );
pServerPassword.bv_len = strlen( pServerPassword.bv_val );
//mysterious code required to prevent crashing
int nsctrls = 0;
LDAPControl c;
c.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
c.ldctl_value.bv_val = NULL;
c.ldctl_value.bv_len = 0;
c.ldctl_iscritical = 0;
LDAPControl sctrl[3];
sctrl[nsctrls] = c;
LDAPControl *sctrls[4];
sctrls[nsctrls] = &sctrl[nsctrls];
sctrls[++nsctrls] = NULL;
LDAPControl **sctrlsp = NULL;
if ( nsctrls )
{
sctrlsp = sctrls;
}
string sBindDN = session.ini["ldap_bind_dn"];
ber_int_t iMsgid;
iErr = ldap_sasl_bind( ld, sBindDN.c_str(), LDAP_SASL_SIMPLE, &pServerPassword, sctrlsp, NULL, &iMsgid );
ber_memfree( pServerPassword.bv_val );
if( iErr != LDAP_SUCCESS )
{
ldap_unbind(ld);
return false;
}
string sBaseDN = session.ini["ldap_base_dn"];
string sFilters = "(uid="+sUserName+")";
LDAPMessage *res;
iErr = ldap_search_ext(ld, // LDAP * ld
&sBaseDN[0], // char * base
LDAP_SCOPE_SUBORDINATE,// int scope
&sFilters[0], // char * filter
NULL, // char * attrs[]
0, // int attrsonly
NULL, // LDAPControl ** serverctrls
NULL, // LDAPControl ** clientctrls
NULL, //struct timeval *timeoutp
LDAP_NO_LIMIT, //int sizelimit
&iMsgid //ber_int_t iMsgid
);
if (iErr != LDAP_SUCCESS)
{
ldap_unbind(ld);
return false;
}
struct timeval zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;
int i, parse_rc, finished = 0, num_entries = 0, num_refs = 0;
char *a, *dn, *matched_msg = NULL, *error_msg = NULL;
BerElement *ber;
char **vals, **referrals;
LDAPControl **serverctrls;
while ( !finished )
{
iErr = ldap_result( ld, iMsgid, LDAP_MSG_ONE, &zerotime, &res );
switch ( iErr )
{
case -1:
Log(1, "BasicAuthenticate: error in ldap_result:{}", ldap_err2string(iErr));
ldap_unbind(ld);
return false;
break;
case 0:
// The timeout period specified by zerotime was exceeded keep polling
Log(1, "BasicAuthenticate: server busy: keep polling");
sleep(1);
break;
case LDAP_RES_SEARCH_ENTRY:
num_entries++;
//Get and print the DN of the entry.
if (( dn = ldap_get_dn( ld, res )) != NULL )
{
Log (1, "ldap_get_dn: {}", dn );
ldap_memfree( dn );
}
for ( a = ldap_first_attribute( ld, res, &ber ); a != NULL; a = ldap_next_attribute( ld, res, ber ) )
{
// Get and print all values for each attribute.
if (( vals = ldap_get_values( ld, res, a )) != NULL )
{
for ( i = 0; vals[ i ] != NULL; i++ )
{
Log (1, "ldap_get_values: {}:{}", a, vals[ i ] );
}
ldap_value_free( vals );
}
ldap_memfree( a );
}
if ( ber != NULL )
{
ber_free( ber, 0 );
}
ldap_msgfree( res );
break;
case LDAP_RES_SEARCH_REFERENCE:
num_refs++;
parse_rc = ldap_parse_reference( ld, res, &referrals, NULL, 1 );
if ( parse_rc != LDAP_SUCCESS )
{
ldap_unbind(ld);
return false;
}
if ( referrals != NULL )
{
for ( i = 0; referrals[ i ] != NULL; i++ )
{
Log(1, "BasicAuthenticate: Search reference:{}", referrals[ i ]);
}
ldap_value_free( referrals );
}
break;
case LDAP_RES_SEARCH_RESULT:
finished = 1;
parse_rc = ldap_parse_result( ld, res, &iErr, &matched_msg, &error_msg, NULL, &serverctrls, 1 );
if ( parse_rc != LDAP_SUCCESS )
{
kDebugLog(1, "BasicAuthenticate: error in ldap_parse_result:{}", ldap_err2string(parse_rc));
ldap_unbind(ld);
return false;
}
break;
default:
break;
}
}
The error I get is:
BasicAuthenticate: server busy keep polling
BasicAuthenticate: error in ldap_parse_result:Server is busy
Am I missing a line of code so the server won't be busy? Is there some sort of incompatibility with the methods I'm using?
I have the following code:
And I would like to select one Ch without the number which has been selected in the other Ch.
For example, in Ch5, "1","2","3","37" can not be selected.
BOOL CMaintenanceHeadDispenserDlg::OnInitDialog()
{
CMaintenanceChildDlg::OnInitDialog();
CRect rc(0, 0, 0, 0);
m_edtDist.Create( NULL, NULL, WS_CHILD|WS_VISIBLE|WS_DISABLED, rc, this, IDC_EDT_MT_HEAD_DISPENSER_DIST );
m_edtDist.SetInputMode( 1 );
m_edtDist.SetInputRange( 999.999, 0.0 );
m_edtDist.EnableRightInputMode( TRUE, 2 );
m_edtOutput.Create(NULL, WS_CHILD|WS_VISIBLE|WS_DISABLED, rc, this, IDC_EDT_MT_HEAD_DISPENSER_OUTPUT);
CDeviceConfigDispenserController* p = CDeviceConfigDispenserController::GetInstance();
SDeviceConfigDispenser d;
p->GetData( d );
m_DispenserChInfoSet.GetChMap(m_mapCh);
for( int i = 0; i < 5; i++ ) {
m_cmbCh[i].ResetContent();
m_cmbCh[i].SetScrollCnt(5);
m_cmbCh[i].SetHitTrace( TRUE );
m_edtCh[i].Create(NULL,NULL,WS_VISIBLE|WS_CHILD|WS_DISABLED,rc,this,IDC_EDT_MT_HEAD_DISPENSER_CH1 + i);
m_edtCh[i].SetLimitTextNum(32);
int itemCnt = 0;
CString strCh;
for( map<int, CString>::iterator it = m_mapCh.begin(); it != m_mapCh.end(); it++ ) {
strCh.Format(_T("%d"), it->first);
m_cmbCh[i].InsertString(itemCnt, strCh);
m_cmbCh[i].SetItemData(itemCnt, it->first);
if( d.nUseCh[i] == it->first ) {
m_cmbCh[i].SetCurSel( itemCnt );
m_edtCh[i].SetString( it->second );
}
itemCnt++;
}
m_rdoCh[i].SetCheck( BST_UNCHECKED );
}
afx_msg LRESULT CMaintenanceHeadDispenserDlg::OnCbxSelchanged(WPARAM wParam, LPARAM lParam)
{
//int j = 0; //ou
for( int i = 0; i < 5; i++ ) {
if( m_cmbCh[i].m_hWnd == (HWND)lParam )
{
int Cnt = m_cmbCh[i].GetCount();
if( (int)wParam < Cnt && (int)wParam >= 0) {
m_cmbCh[i].SetCurSel( (int)wParam );
int Index = (int)m_cmbCh[i].GetItemData( m_cmbCh[i].GetCurSel() );
map<int, CString>::iterator it = m_mapCh.find( Index );
if( it != m_mapCh.end() ) {
m_edtCh[i].SetString( it->second );
}
break;
}
}
}
Using the following code to update my application with an external exe file, I get paint corruption (not update or refresing) to window under -which is the main app and the caller- when I move this window. It seems that under Windows 7 works fine but under window XP I have this problem.
void CMainFrame::OnBtnUpdateApp() {
SHELLEXECUTEINFO lpExecInfo;
DWORD dwExitCode;
HINSTANCE hProcess = 0;
BOOL bResult;
ZeroMemory(&lpExecInfo,sizeof(lpExecInfo));
lpExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
lpExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
lpExecInfo.hwnd = GetSafeHwnd();
lpExecInfo.lpVerb = _T("open");
lpExecInfo.lpFile = _T("Update.exe");
lpExecInfo.lpParameters = _T("");
lpExecInfo.lpDirectory = _T("");
lpExecInfo.nShow = SW_SHOWNORMAL;
lpExecInfo.hInstApp = NULL;
lpExecInfo.hProcess = hProcess;
bResult = ShellExecuteEx(&lpExecInfo);
if(bResult) {
WaitForSingleObject( lpExecInfo.hProcess, INFINITE );
if (!GetExitCodeProcess(lpExecInfo.hProcess, &dwExitCode)) {
//failed to terminate normally
}
CloseHandle(lpExecInfo.hProcess);
} else {
//failed to execute the exe file
}
}
What seems to be wrong here ?
You're not processing any window messages during WaitForSingleObject.
Re the difference between Windows XP and Windows 7, the Desktop Window Manager technology in Windows 7 was introduced with Windows Vista, and was not available in Windows XP. Essentially it provides a layer of indirection between each app's painting actions and the result on screen.
A reasonable way to launch and wait for a program is to disable the main window the window's user interface parts and then poll the program's exit status in a peek-message loop.
Example, except that it uses CreateProcess (I coded it up without remembering to check the question, and now it's pretty late in the evening, but better with imperfect help than no help, I think):
#include <windows.h> // UNICODE, NOMINMAX, STRICT, WIN32_LEAN_AND_MEAN
#include <windowsx.h> // Message cracker macros, e.g. HANDLE_WM_DESTROY
#include <assert.h>
#include <stdexcept>
#include <string>
using namespace std;
auto hopefully( bool const condition ) -> bool { return condition; }
auto fail( string const& s ) -> bool { throw runtime_error( s ); }
struct Window_class_id
{
ATOM value;
auto as_pointer() const -> wchar_t const* { return MAKEINTATOM( value ); }
};
auto get_message( MSG& m )
-> bool
{
int const result = GetMessage( &m, 0, 0, 0 );
hopefully( result != -1 )
|| fail( "GetMessage failed" );
return !!result;
}
auto peek_message( MSG& m )
-> bool
{
int const result = PeekMessage( &m, 0, 0, 0, TRUE );
hopefully( result != -1 )
|| fail( "PeekMessage failed" );
return !!result;
}
void empty_message_queue()
{
MSG m;
while( peek_message( m ) )
{
TranslateMessage( &m );
DispatchMessage( &m );
}
}
auto dispatch_messages()
-> DWORD // Exit code from WM_QUIT
{
MSG msg;
while( get_message( msg ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
assert( msg.message == WM_QUIT );
return msg.wParam;
}
auto run( wchar_t const command[] )
-> HANDLE
{
wstring commandline = command;
hopefully( commandline.length() > 0 )
|| fail( "run: Empty command line" );
STARTUPINFO in_params = { sizeof( STARTUPINFO ) };
PROCESS_INFORMATION out_params = {};
bool const success = !!CreateProcess(
nullptr, // app name
&commandline[0],
nullptr, // process attributes
nullptr, // thread attributes
false, // inherit handles
0, // creation flags
nullptr, // environment block
nullptr, // current directory
&in_params, // startup info
&out_params // process info
);
hopefully( success )
|| fail( "run: CreateProcess failed" );
CloseHandle( out_params.hThread );
return out_params.hProcess;
}
namespace main_window
{
namespace command_id {
int const run_fun = 101;
} // namespace command
namespace run_button {
int const id = command_id::run_fun;
} // namespace run_button
namespace command {
void run_fun( HWND const window )
{
EnableWindow( GetDlgItem( window, run_button::id ), false );
UpdateWindow( window );
empty_message_queue();
HANDLE const process = run( L"notepad" );
for( ;; )
{
DWORD const result = WaitForSingleObject( process, 100 );
if( result == WAIT_OBJECT_0 )
{
break;
}
empty_message_queue();
}
CloseHandle( process );
EnableWindow( GetDlgItem( window, run_button::id ), true );
}
} // namespace command
void on_command( HWND const window, int const id )
{
switch( id )
{
case command_id::run_fun: return command::run_fun( window );
}
}
void on_wm_command(
HWND const window,
int const control_or_command_id,
HWND const control,
UINT const notification_code
)
{
if( control == 0 )
{
int const command_id = control_or_command_id;
on_command( window, command_id );
}
else
{
int const control_id = control_or_command_id;
switch( control_id )
{
case run_button::id:
if( notification_code == BN_CLICKED )
{
int const command_id = control_id;
on_command( window, command_id );
}
}
}
}
auto on_wm_create( HWND const window, CREATESTRUCT const* const p_params )
-> bool // `true` if creation succeeded.
{
(void) p_params;
HWND const button_handle = CreateWindow(
L"button", L"Run the fun", WS_CHILD | WS_VISIBLE,
10, 10, 120, 26,
window, // parent
reinterpret_cast<HMENU>( run_button::id ),
GetModuleHandle( 0 ),
0 // lpParam
);
return (button_handle != 0);
}
void on_wm_destroy( HWND const window )
{
(void) window;
PostQuitMessage( 0 );
}
auto CALLBACK message_handler(
HWND const window,
UINT const message_id,
WPARAM const word_param,
LPARAM const long_param
)
-> LRESULT
{
switch( message_id )
{
case WM_COMMAND: return HANDLE_WM_COMMAND(
window, word_param, long_param, on_wm_command );
case WM_CREATE: return HANDLE_WM_CREATE(
window, word_param, long_param, on_wm_create );
case WM_DESTROY: return HANDLE_WM_DESTROY(
window, word_param, long_param, on_wm_destroy );
}
return DefWindowProc( window, message_id, word_param, long_param );
}
} // namespace main_window
auto register_window_class()
-> Window_class_id
{
WNDCLASS params = {};
params.style = CS_DBLCLKS;
params.lpfnWndProc = main_window::message_handler;
params.hInstance = GetModuleHandle( 0 );
params.hIcon = LoadIcon( 0, IDI_APPLICATION );
params.hCursor = LoadCursor( 0, IDC_ARROW );
params.hbrBackground = reinterpret_cast<HBRUSH>( COLOR_WINDOW );
params.lpszClassName = L"MainWindow_class";
ATOM const id = RegisterClass( ¶ms );
hopefully( id != 0 )
|| fail( "RegisterClass failed" );
return {id};
}
auto create_window( Window_class_id const& class_id )
-> HWND
{
HWND const handle = CreateWindow(
class_id.as_pointer(),
L"Fun run",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 380, 221, // x, y, w, h
0, 0, // parent, menu
GetModuleHandle( 0 ),
0 // lpParam
);
hopefully( handle != 0 )
|| fail( "CreateWindow failed" );
return handle;
}
void cpp_main()
{
Window_class_id const class_id = register_window_class();
HWND const window = create_window( class_id );
ShowWindow( window, SW_SHOWDEFAULT );
int const exit_code = static_cast<int>( dispatch_messages() );
hopefully( exit_code == 0 )
|| fail( "WM_QUIT indicated failure" );
}
auto main() -> int
{
try{ cpp_main(); } catch( ... ) { return E_FAIL; }
return 0;
}
There are some similar topics on SO, but I haven't found all I need.
I have the following C++ Code:
string getConsoleOutput(string command)
{
string data;
File *fp;
char var[512];
fp = _popen(command.c_str(), "r");
while (fgets(var, sizeof(var), fp) != NULL)
{
data += var;
}
_pclose(fp);
return data;
}
The problem is that every time I send a console command to this function, the command line pops up.
I want to send a command to the Console and get the output without seeing a Console Window.
EDIT:
I tried out libexec, but it is too complex for my needs
I also read about WinExec and CreateProcess, but I haven't found a way to get the output
If it is okay with a little flash on the screen, then just include a command to hide the window. Since AFAIK Windows doesn't itself offer such a command (although it may be lurking in the deeps of Powershell), you will have to create it. But that's trivial:
#define UNICODE
#define NOMINMAX
#include <windows.h>
auto main() -> int
{
ShowWindow( GetConsoleWindow(), SW_HIDE );
}
I've tested that the _popen functionality works OK with hidden window.
And contrary to the documentation, it apparently also works OK for a GUI subsystem application, although I didn't test more than a dir command.
If the flash is unacceptable, then you can use CreateProcess to fire up a hidden command intepreter window, and low level Windows pipes to catch the output.
Sorry, I first wrote a suggestion here about COMSPEC and a GUI subsystem faux command interpreter, which works as far as I tested it, but it would just involve the above again for catching the command interpreter output. I.e. using _popen in the main program would then just be added complication and inefficiency. Better to do it directly at the API level.
An example.
Disclaimer: I am pretty sure I'm doing something wrong here, because when the command process terminates the pipe should generate EOF, no bytes read. Instead the ReadFile call would then just hang, so I had to add a very ugly wait-for-data-or-process-termination loop before calling ReadFile. On the other hand, I remember that Windows had some bugs related to pipes and EOF. So pretty sure is not 100% sure, but I haven't had time to check out MS example.
#define NOMINMAX
#define STRICT
#define UNICODE
#include <windows.h>
#include <stdexcept>
#include <stdio.h>
#include <string>
using namespace std;
auto hopefully( const bool condition ) -> bool { return condition; }
auto fail( const string& message ) -> bool { throw runtime_error( message ); }
struct Non_copyable
{
Non_copyable& operator=( const Non_copyable& ) = delete;
Non_copyable( const Non_copyable& ) = delete;
Non_copyable() {}
Non_copyable( Non_copyable&& ) {}
};
struct Process
: Non_copyable
{
HANDLE handle;
~Process() { CloseHandle( handle ); }
Process( const HANDLE h = 0 ): handle( h ) {}
Process( Process&& other ): handle( other.handle ) { other.handle = 0; }
};
auto environment_var( const wstring& name )
-> wstring
{
const DWORD buffer_size = GetEnvironmentVariable( name.c_str(), nullptr, 0 );
hopefully( buffer_size > 0 )
|| fail( "environment_var: GetEnvironmentVariable failed 1st call." );
wstring result( buffer_size + 1, L'#' );
const DWORD n_characters = GetEnvironmentVariable(
name.c_str(), &result[0], result.size()
);
hopefully( n_characters > 0 )
|| fail( "environment_var: GetEnvironmentVariable failed 2nd call." );
result.resize( n_characters ); // Just for good measure.
return result;
}
auto exit_code_of( const HANDLE process )
-> int
{
DWORD code = E_FAIL;
GetExitCodeProcess( process, &code );
return code;
}
auto has_terminated( const HANDLE process )
-> bool
{ return exit_code_of( process ) != STILL_ACTIVE; }
auto start_command( const wstring& command, const HANDLE output_handle = INVALID_HANDLE_VALUE )
-> Process
{
const wstring com_spec = environment_var( L"COMSPEC" );
wstring command_line = com_spec + L" /c " + command; // Can not be `const`.
STARTUPINFO params = { sizeof( STARTUPINFO ) };
if( output_handle != INVALID_HANDLE_VALUE )
{
const HANDLE nul = CreateFile( L"nul", GENERIC_ALL, 0, nullptr, OPEN_EXISTING, 0, 0 );
params.dwFlags = STARTF_USESTDHANDLES;
params.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
params.hStdOutput = output_handle;
params.hStdError = GetStdHandle( STD_ERROR_HANDLE );
}
PROCESS_INFORMATION info = {};
bool const process_was_created = !!CreateProcess(
nullptr, // LPCTSTR lpApplicationName,
&command_line[0], // LPTSTR lpCommandLine,
nullptr, // LPSECURITY_ATTRIBUTES lpProcessAttributes,
nullptr, // LPSECURITY_ATTRIBUTES lpThreadAttributes,
true, // BOOL bInheritHandles,
CREATE_NO_WINDOW, // DWORD dwCreationFlags,
nullptr, // LPVOID lpEnvironment,
nullptr, // LPCTSTR lpCurrentDirectory,
¶ms, // LPSTARTUPINFO lpStartupInfo,
&info // LPPROCESS_INFORMATION lpProcessInformation
);
if( not process_was_created ) { return 0; }
CloseHandle( info.hThread );
return info.hProcess;
}
auto command_result( const wstring& command )
-> string
{
struct Pipe
{
HANDLE read_handle = 0;
HANDLE write_handle = 0;
~Pipe() { CloseHandle( read_handle ); CloseHandle( write_handle ); }
};
Pipe pipe;
SECURITY_ATTRIBUTES params = { sizeof( SECURITY_ATTRIBUTES ) };
params.bInheritHandle = TRUE;
CreatePipe( &pipe.read_handle, &pipe.write_handle, ¶ms, 0 )
|| fail( "command_result: CreatePipe failed" );
SetHandleInformation( pipe.read_handle, HANDLE_FLAG_INHERIT, 0 ); // Inheritance ungood.
const Process process = { start_command( command, pipe.write_handle ) };
if( process.handle == 0 ) { return ""; }
string result;
for( ;; )
{
// Wait for data to become available or process terminated, to avoid hanging.
for( ;; )
{
DWORD n_bytes_available = 0;
const bool ok = !!PeekNamedPipe(
pipe.read_handle, nullptr, 0, nullptr, &n_bytes_available, nullptr
);
if( ok && n_bytes_available > 0 ) { break; }
if( has_terminated( process.handle ) ) { return result; }
Sleep( 125 );
}
char buffer[4096];
DWORD n_bytes_read = 0;
SetLastError( 0 );
ReadFile( pipe.read_handle, buffer, sizeof( buffer ), &n_bytes_read, nullptr )
|| fail( "command_result: ReadFile failed" );
const auto last_read_error = GetLastError();
if( last_read_error != 0 ) { break; }
if( n_bytes_read == 0 ) { break; }
result.append( buffer, n_bytes_read );
}
return result;
}
auto main() -> int
{
try
{
const string result = command_result( L"dir *" );
const wstring text( result.begin(), result.end() );
MessageBox( 0, text.c_str(), L"Result:", MB_SETFOREGROUND );
return 0;
}
catch( const exception& x )
{
MessageBoxA( 0, x.what(), "Oops, an exception", MB_ICONERROR | MB_SETFOREGROUND );
}
return E_FAIL;
}
I'm trying to read a config file like this:
rawfile=input.raw
encfile=encoded.enc
decfile=decoded.raw
width=512
height=512
rle=1
quantfile=matrix.txt
logfile=log.txt
Having this function:
void Compression::readConfigFile(char * input)
{
string lineBuf;
string optionBuf;
std::ifstream confFile(input);
if ( confFile.is_open() )
{
while ( getline( confFile, lineBuf ) )
{
optionBuf = "rawfile=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length() );
this->rawfile = lineBuf.c_str();
}
optionBuf = "encfile=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length() );
this->encfile = lineBuf.c_str();
}
optionBuf = "decfile=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length() );
this->encfile = lineBuf.c_str();
}
optionBuf = "width=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length() );
this->width = atoi( lineBuf.c_str() );
}
optionBuf = "height=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length() );
this->height = atoi( lineBuf.c_str() );
}
optionBuf = "rle=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length() );
this->rle = atoi( lineBuf.c_str() );
}
optionBuf = "quantfile=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length());
this->matrix = lineBuf.c_str();
}
optionBuf = "logfile=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length() );
this->logfile = lineBuf.c_str();
}
confFile.close();
}
}
else
cout << "Can't open file: " << input << endl;
}
But it doesn't work. My ints are 0 or some big number. My strings are still empty.
Can someone help me please?
Kind regards,
shouldn't you rather close the file outside of the while loop ?
while() {
...
}
confFile.close();