static uintptr_t CPROC SetDefaultPath( uintptr_t psv, arg_list args ) { PARAM( args, CTEXTSTR, path ); if( !l.target_path ) { // otherwise it was already set on the commandline l.target_path = ExpandPath( path ); SetCurrentPath( l.target_path ); } return psv; }
int CPROC CHANGEDIR( PSENTIENT ps, PTEXT parameters ) { PTEXT pDir, pDir1; pDir1 = MacroDuplicateEx( ps, parameters, TRUE, TRUE ); if( pDir1 ) pDir = BuildLine( pDir1 ); else return FALSE; LineRelease( pDir1 ); if( SetCurrentPath( GetText( pDir ) ) ) { if( ps->CurrentMacro ) ps->CurrentMacro->state.flags.bSuccess = TRUE; else { DECLTEXT( msg, WIDE("Changed directory successfully.") ); { TEXTCHAR buf[257]; GetCurrentPath( buf, sizeof( buf ) ); SetDefaultFilePath( buf ); } EnqueLink( &ps->Command->Output, &msg ); } } else { if( !ps->CurrentMacro ) { DECLTEXT( msg, WIDE("Failed to change directory.") ); EnqueLink( &ps->Command->Output, &msg ); } } LineRelease( pDir ); return FALSE; }
// Run a program completely detached from the current process // it runs independantly. Program does not suspend until it completes. // No way at all to know if the program works or fails. SYSTEM_PROC( PTASK_INFO, LaunchPeerProgramExx )( CTEXTSTR program, CTEXTSTR path, PCTEXTSTR args , int flags , TaskOutput OutputHandler , TaskEnd EndNotice , uintptr_t psv DBG_PASS ) { PTASK_INFO task; if( program && program[0] ) { #ifdef WIN32 int launch_flags = ( ( flags & LPP_OPTION_NEW_CONSOLE ) ? CREATE_NEW_CONSOLE : 0 ) | ( ( flags & LPP_OPTION_NEW_GROUP ) ? CREATE_NEW_PROCESS_GROUP : 0 ) ; PVARTEXT pvt = VarTextCreateEx( DBG_VOIDRELAY ); PTEXT cmdline; PTEXT final_cmdline; LOGICAL needs_quotes; TEXTSTR expanded_path = ExpandPath( program ); char *new_path; TEXTSTR expanded_working_path = path?ExpandPath( path ):ExpandPath( WIDE(".") ); int first = TRUE; //TEXTCHAR saved_path[256]; task = (PTASK_INFO)AllocateEx( sizeof( TASK_INFO ) DBG_RELAY ); MemSet( task, 0, sizeof( TASK_INFO ) ); task->psvEnd = psv; task->EndNotice = EndNotice; if( l.ExternalFindProgram ) { new_path = l.ExternalFindProgram( expanded_path ); if( new_path ) { Release( expanded_path ); expanded_path = new_path; } } #ifdef _DEBUG xlprintf(LOG_NOISE)( WIDE("%s[%s]"), path, expanded_working_path ); #endif if( StrCmp( path, WIDE(".") ) == 0 ) { path = NULL; Release( expanded_working_path ); expanded_working_path = NULL; } if( expanded_path && StrChr( expanded_path, ' ' ) ) needs_quotes = TRUE; else needs_quotes = FALSE; if( needs_quotes ) vtprintf( pvt, WIDE( "\"" ) ); /* if( !IsAbsolutePath( expanded_path ) && expanded_working_path ) { //lprintf( "needs working path too" ); vtprintf( pvt, WIDE("%s/"), expanded_working_path ); } */ vtprintf( pvt, WIDE("%s"), expanded_path ); if( needs_quotes ) vtprintf( pvt, WIDE( "\"" ) ); if( flags & LPP_OPTION_FIRST_ARG_IS_ARG ) ; else { if( args && args[0] )// arg[0] is passed with linux programs, and implied with windows. args++; } while( args && args[0] ) { if( args[0][0] == 0 ) vtprintf( pvt, WIDE( " \"\"" ) ); else if( StrChr( args[0], ' ' ) ) vtprintf( pvt, WIDE(" \"%s\""), args[0] ); else vtprintf( pvt, WIDE(" %s"), args[0] ); first = FALSE; args++; } cmdline = VarTextGet( pvt ); vtprintf( pvt, WIDE( "cmd.exe /c %s" ), GetText( cmdline ) ); final_cmdline = VarTextGet( pvt ); VarTextDestroy( &pvt ); MemSet( &task->si, 0, sizeof( STARTUPINFO ) ); task->si.cb = sizeof( STARTUPINFO ); #ifdef _DEBUG xlprintf(LOG_NOISE)( WIDE( "quotes?%s path [%s] program [%s] [cmd.exe (%s)]"), needs_quotes?WIDE( "yes"):WIDE( "no"), expanded_working_path, expanded_path, GetText( final_cmdline ) ); #endif /* if( path ) { GetCurrentPath( saved_path, sizeof( saved_path ) ); SetCurrentPath( path ); } */ task->OutputEvent = OutputHandler; if( OutputHandler ) { SECURITY_ATTRIBUTES sa; sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; sa.nLength = sizeof( sa ); CreatePipe( &task->hReadOut, &task->hWriteOut, &sa, 0 ); //CreatePipe( &hReadErr, &hWriteErr, &sa, 0 ); CreatePipe( &task->hReadIn, &task->hWriteIn, &sa, 0 ); task->si.hStdInput = task->hReadIn; task->si.hStdError = task->hWriteOut; task->si.hStdOutput = task->hWriteOut; task->si.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; if( !( flags & LPP_OPTION_DO_NOT_HIDE ) ) task->si.wShowWindow = SW_HIDE; else task->si.wShowWindow = SW_SHOW; } else { task->si.dwFlags |= STARTF_USESHOWWINDOW; if( !( flags & LPP_OPTION_DO_NOT_HIDE ) ) task->si.wShowWindow = SW_HIDE; else task->si.wShowWindow = SW_SHOW; } { HINSTANCE hShellProcess = 0; int success = 0; #ifdef WIN32 if( flags & LPP_OPTION_IMPERSONATE_EXPLORER ) { HANDLE hExplorer = GetImpersonationToken(); if( ( CreateProcessAsUser( hExplorer, NULL //program , GetText( cmdline ) , NULL, NULL, TRUE , launch_flags | CREATE_NEW_PROCESS_GROUP , NULL , expanded_working_path , &task->si , &task->pi ) || FixHandles(task) || DumpError() ) || ( CreateProcessAsUser( hExplorer, program , GetText( cmdline ) , NULL, NULL, TRUE , launch_flags | CREATE_NEW_PROCESS_GROUP , NULL , expanded_working_path , &task->si , &task->pi ) || FixHandles(task) || DumpError() ) || ( CreateProcessAsUser( hExplorer, program , NULL // GetText( cmdline ) , NULL, NULL, TRUE , launch_flags | CREATE_NEW_PROCESS_GROUP , NULL , expanded_working_path , &task->si , &task->pi ) || FixHandles(task) || DumpError() ) || ( CreateProcessAsUser( hExplorer, WIDE( "cmd.exe" ) , GetText( final_cmdline ) , NULL, NULL, TRUE , launch_flags | CREATE_NEW_PROCESS_GROUP , NULL , expanded_working_path , &task->si , &task->pi ) || FixHandles(task) || DumpError() ) ) { success = 1; } CloseHandle( hExplorer ); } else #endif { if( ( CreateProcess( NULL //program , GetText( cmdline ) , NULL, NULL, TRUE , launch_flags | ( OutputHandler?CREATE_NO_WINDOW:0 )//CREATE_NEW_PROCESS_GROUP , NULL , expanded_working_path , &task->si , &task->pi ) || FixHandles(task) || DumpError() ) || ( CreateProcess( program , GetText( cmdline ) , NULL, NULL, TRUE , launch_flags | ( OutputHandler?CREATE_NO_WINDOW:0 )//CREATE_NEW_PROCESS_GROUP , NULL , expanded_working_path , &task->si , &task->pi ) || FixHandles(task) || DumpError() ) || ( CreateProcess( program , NULL // GetText( cmdline ) , NULL, NULL, TRUE , launch_flags | ( OutputHandler?CREATE_NO_WINDOW:0 )//CREATE_NEW_PROCESS_GROUP , NULL , expanded_working_path , &task->si , &task->pi ) || FixHandles(task) || DumpError() ) || ( TryShellExecute( task, expanded_working_path, program, cmdline ) ) || ( CreateProcess( NULL//WIDE( "cmd.exe" ) , GetText( final_cmdline ) , NULL, NULL, TRUE , launch_flags | ( OutputHandler?CREATE_NO_WINDOW:0 )//CREATE_NEW_PROCESS_GROUP , NULL , expanded_working_path , &task->si , &task->pi ) || FixHandles(task) || DumpError() ) || 0 ) { success = 1; } } if( success ) { //CloseHandle( task->hReadIn ); //CloseHandle( task->hWriteOut ); #ifdef _DEBUG xlprintf(LOG_NOISE)( WIDE("Success running %s[%s] in %s (%p): %d"), program, GetText( cmdline ), expanded_working_path, task->pi.hProcess, GetLastError() ); #endif if( OutputHandler ) { task->hStdIn.handle = task->hWriteIn; task->hStdIn.pLine = NULL; //task->hStdIn.pdp = pdp; task->hStdIn.hThread = 0; task->hStdIn.bNextNew = TRUE; task->hStdOut.handle = task->hReadOut; task->hStdOut.pLine = NULL; //task->hStdOut.pdp = pdp; task->hStdOut.bNextNew = TRUE; task->hStdOut.hThread = ThreadTo( HandleTaskOutput, (uintptr_t)task ); ThreadTo( WaitForTaskEnd, (uintptr_t)task ); } else { //task->hThread = ThreadTo( WaitForTaskEnd, (uintptr_t)task ); } } else { xlprintf(LOG_NOISE)( WIDE("Failed to run %s[%s]: %d"), program, GetText( cmdline ), GetLastError() ); CloseHandle( task->hWriteIn ); CloseHandle( task->hReadIn ); CloseHandle( task->hWriteOut ); CloseHandle( task->hReadOut ); CloseHandle( task->pi.hProcess ); CloseHandle( task->pi.hThread ); Release( task ); task = NULL; } } LineRelease( cmdline ); LineRelease( final_cmdline ); Release( expanded_working_path ); Release( expanded_path ); /* if( path ) SetCurrentPath( saved_path ); */ return task; #endif #ifdef __LINUX__ { pid_t newpid; TEXTCHAR saved_path[256]; xlprintf(LOG_ALWAYS)( WIDE("Expand Path was not implemented in linux code!") ); task = (PTASK_INFO)Allocate( sizeof( TASK_INFO ) ); MemSet( task, 0, sizeof( TASK_INFO ) ); task->psvEnd = psv; task->EndNotice = EndNotice; task->OutputEvent = OutputHandler; if( OutputHandler ) { pipe(task->hStdIn.pair); task->hStdIn.handle = task->hStdIn.pair[1]; pipe(task->hStdOut.pair); task->hStdOut.handle = task->hStdOut.pair[0]; } // always have to thread to taskend so waitpid can clean zombies. ThreadTo( WaitForTaskEnd, (uintptr_t)task ); if( path ) { GetCurrentPath( saved_path, sizeof( saved_path ) ); SetCurrentPath( path ); } if( !( newpid = fork() ) ) { char *_program = CStrDup( program ); // in case exec fails, we need to // drop any registered exit procs... //close( task->hStdIn.pair[1] ); //close( task->hStdOut.pair[0] ); //close( task->hStdErr.pair[0] ); if( OutputHandler ) { dup2( task->hStdIn.pair[0], 0 ); dup2( task->hStdOut.pair[1], 1 ); dup2( task->hStdOut.pair[1], 2 ); } DispelDeadstart(); //usleep( 100000 ); execve( _program, (char *const*)args, environ ); lprintf( WIDE( "Direct execute failed... trying along path..." ) ); { char *tmp = strdup( getenv( "PATH" ) ); char *tok; for( tok = strtok( tmp, ":" ); tok; tok = strtok( NULL, ":" ) ) { char fullname[256]; snprintf( fullname, sizeof( fullname ), "%s/%s", tok, _program ); lprintf( WIDE( "program:[%s]" ), fullname ); ((char**)args)[0] = fullname; execve( fullname, (char*const*)args, environ ); } Release( tmp ); } if( OutputHandler ) { close( task->hStdIn.pair[0] ); close( task->hStdOut.pair[1] ); } //close( task->hWriteErr ); close( 0 ); close( 1 ); close( 2 ); lprintf( WIDE( "exec failed - and this is ALLL bad... %d" ), errno ); //DebugBreak(); // well as long as this runs before // the other all will be well... task = NULL; // shit - what can I do now?! exit(0); // just in case exec fails... need to fault this. } else { if( OutputHandler ) { close( task->hStdIn.pair[0] ); close( task->hStdOut.pair[1] ); } } if( OutputHandler ) ThreadTo( HandleTaskOutput, (uintptr_t)task ); task->pid = newpid; lprintf( WIDE("Forked, and set the pid..") ); // how can I know if the command failed? // well I can't - but the user's callback will be invoked // when the above exits. if( path ) { // if path is NULL we didn't change the path... SetCurrentPath( saved_path ); } return task; } #endif } return FALSE; }
SaneWinMain( argc, argv ) { int nowait = 0; int task_monitor = 0; int noinput = 0; if( argc < 2 ) { #ifdef WIN32 const TEXTCHAR * const args[] ={ WIDE("cmd.exe"), NULL }; #else const TEXTCHAR * const args[] ={ WIDE("/bin/sh"), NULL }; #endif if( !( task = LaunchPeerProgram( args[0], NULL, args, output, ended, 0 ) ) ) done = 1; } else { int delay = 0; int offset = 1; while( argv[offset] && argv[offset][0] == '-' ) { if( StrCaseCmp( argv[offset]+1, WIDE("nowait") ) == 0 ) nowait = 1; if( StrCaseCmp( argv[offset]+1, WIDE("taskmon") ) == 0 ) task_monitor = 1; if( StrCaseCmp( argv[offset]+1, WIDE("noin") ) == 0 ) noinput = 1; if( StrCaseCmp( argv[offset]+1, WIDE("local") ) == 0 ) { SetCurrentPath( OSALOT_GetEnvironmentVariable( WIDE("MY_LOAD_PATH") ) ); } if( StrCaseCmp( argv[offset]+1, WIDE("delay") ) == 0 ) { delay = atoi( argv[offset+1] ); offset++; // used an extra parameter } offset++; } if( delay ) WakeableSleep( delay ); if( offset < argc ) { if( !( task = LaunchPeerProgram( argv[offset], NULL, argv + offset, noinput?NULL:output, ended, 0 ) ) ) done = 1; } else { #ifdef WIN32 const TEXTCHAR * const args[] ={ WIDE("cmd.exe"), NULL }; #else const TEXTCHAR * const args[] ={ WIDE("/bin/sh"), NULL }; #endif if( !( task = LaunchPeerProgram( args[0], NULL, args, noinput?NULL:output, ended, 0 ) ) ) done = 1; } } main_thread = MakeThread(); while( !done ) { TEXTCHAR buf[256]; if( nowait ) WakeableSleep( 1000 ); else { if( !noinput ) { if( fgets( buf, 256, stdin ) ) { pprintf( task, WIDE("%s"), buf ); } } else nowait = 1; } } if( task_monitor ) SendMessage( FindWindow( WIDE("TaskMonClass"), WIDE("Task Completion Monitor") ), WM_USER+500, 0, 0 ); fprintf( stdout, WIDE("Shell Completed.") ); return 0; }
BOOL Shell::Execute_Cd( const TStringVector& cmdparts, tstring& reply ) { if (cmdparts.size() == 1) { reply = m_currentPath; return TRUE; } else if (cmdparts.size() > 1) { tstring target = cmdparts[1]; if (target.size() == 2 && target[1] == ':') { //切换当前分区 int index = 0; TCHAR partition = target[0]; if (partition >= 'a' && partition <= 'z') index = partition - 'a'; else if (partition >= 'A' && partition <= 'Z') index = partition - 'A'; else { reply = _T("invalid partition"); return FALSE; } if (! m_partitions[index].bValid) { reply = _T("invalid partition"); return FALSE; } m_currentPath = m_partitions[index].curPath; reply = m_currentPath; return TRUE; } else { tstring testPath; if (target.size() > 2 && target[1] == ':') { //绝对路径 testPath = target; } else { //相对路径 testPath = m_currentPath; testPath += '\\'; testPath += target; MakeAbsolutePath(testPath.c_str(), testPath); } BOOL bExists = FALSE; BOOL bDir = FALSE; if (FileExistsInClient(testPath.c_str(), bExists, bDir)) { if (bExists && bDir) { SetCurrentPath(testPath.c_str()); reply = m_currentPath; return TRUE; } else { reply = _T("invalid filepath"); return FALSE; } } else { reply = _T("等待客户端回应超时"); return FALSE; } } } return FALSE; }
//------------------------------------------------ // 파일의 리스트 및 각 파일에 대한 자세한 정보를 // 함께 저장하게 됨 // data.h파일에 해당 구조체를 선언한다. //-------------------------------------------------- void CMyExplorerDoc::SelectTreeViewFolder(CString strFullName) { LIST_VIEW* pListView; CFileFind ff; // 사용자가 폴더를 선택할 때마다 파일 리스트를 // 새로 업데이트 해야 함 // 따라서 기존 정보를 모두 삭제한다. if (m_pFileList != NULL) RemoveAllFileList(); m_pFileList = new CObList; SetCurrentPath(strFullName); strFullName += "*.*"; if (ff.FindFile(strFullName) == TRUE) { BOOL bFlag = TRUE; while(bFlag == TRUE) { bFlag = ff.FindNextFile(); // 디렉토리 , 도트파일이면 다시 찾음 if (ff.IsDirectory() || ff.IsDots()) continue; // 파일 정보를 알아내서LIST_VIEW 구조체에 // 저장한 후 // 그것을 모두 m_pFileList에 저장한다. pListView = new LIST_VIEW; InitListViewStruct(pListView); pListView->strName = ff.GetFileName(); pListView->strPath = ff.GetFilePath(); CString strName = pListView->strName; CString strExt = ff.GetFileTitle(); int nNum = strName.GetLength() - strExt.GetLength(); if (nNum == 0) strExt = ""; else strExt = strName.Right(nNum - 1); pListView->strKind = strExt + " 파일"; pListView->dwFileSize = ff.GetLength(); CTime time; if (ff.GetCreationTime(time) == TRUE) pListView->tCreateTime = time; if (ff.GetLastAccessTime(time) == TRUE) pListView->tLastAccessTime = time; if (ff.GetLastWriteTime(time) == TRUE) pListView->tLastWriteTime = time; if (ff.IsHidden() == TRUE) pListView->bIsHidden = TRUE; if (ff.IsReadOnly() == TRUE) pListView->bIsReadOnly = TRUE; if (ff.IsArchived() == TRUE) pListView->bIsArchived = TRUE; if (ff.IsSystem() == TRUE) pListView->bIsSystem = TRUE; m_pFileList->AddTail((CObject*)pListView); } } ff.Close(); //------------------------------ m_pExpListView->SetFileList(); //------------------------------------- }
int main( int argc, char **argv ) { int n; g.dsn = "version.db"; g.build_id = INVALID_INDEX; g.flags.use_common_build = 1; // force this flag... for( n = 1; n < argc; n++ ) { if( argv[n][0] == '-' ) { switch( argv[n][1] ) { case 'n': case 'N': g.flags.skip_push = 1; break; case 'b': case 'B': if( argv[n][2] ) g.build_id = atoi( argv[n] + 2); else if( n < (argc-1) ) g.build_id = atoi( argv[++n] ); break; case 'u': case 'U': if( !l.odbc ) l.odbc = ConnectToDatabase( g.dsn ); IncrementBuild( l.odbc ); break; case 'd': case 'D': if( argv[n][2] ) g.dsn = argv[n] + 2; else if( n < (argc-1) ) g.dsn = argv[++n]; if( l.odbc ) CloseDatabase( l.odbc ); l.odbc = ConnectToDatabase( g.dsn ); lprintf( "new db %p", l.odbc ); break; case 'v': case 'V': if( !l.odbc ) l.odbc = ConnectToDatabase( g.dsn ); if( argv[n][2] ) SetCurrentVersion( l.odbc, argv[n]+2 ); else if( n < (argc-1) ) SetCurrentVersion( l.odbc, argv[++n] ); break; } } else { PPROJECT_ROOT project_root = New( PROJECT_ROOT ); if( !l.odbc ) l.odbc = ConnectToDatabase( g.dsn ); project_root->root_path = argv[n]; project_root->project_id = CheckProjectTable( l.odbc, argv[n] ); SetCurrentPath( project_root->root_path ); // GetBuildVersion also does the hg tag.... project_root->build_id = GetBuildVersion( l.odbc, project_root->project_id ); if( !g.flags.skip_push ) System( "hg push", NULL, 0 ); } } if( n == 1 ) { printf( "Usage: %s [-b build_id] [-u] [-v version] [-d dsn] [-n] [project]\n", argv[0] ); printf( " option order matters; such that - option must preceed the project otherwise does not matter\n" ); printf( " -b sets the current build number\n" ); printf( " build_id is an integer; it specifies the least significant build digits\n" ); printf( " -v sets the major version part\n" ); printf( " version is a string; it specifies the major part of the version\n" ); printf( " -d specifies the database; if not specified will be version.db in the current working directory.\n" ); printf( " dsn is a string; it is the data source name (.db extension will trigger sqlite)\n" ); printf( " project is a string; it specifies the application name for the versioning\n" ); printf( " -u increments the current build number.\n" ); printf( " -n skips running 'hg push' after 'hg tag'\n" ); printf( " using -v will set the current default for the next update\n" ); printf( " using -b sets the current so the tool can be called without -u to rebuild.\n" ); } return 0; }
static void CPROC DoStart2( void ) # endif { #ifdef WIN32 //lprintf( WIDE("Begin impersonation...") ); ImpersonateInteractiveUser(); #endif //lprintf( WIDE("Begin impersonation2...") ); # ifndef LOAD_LIBNAME if( my_argc > 1 ) { hModule = LoadFunction( libname = my_argv[1], NULL ); if( hModule ) arg_offset++; } # endif if( !hModule ) { # ifdef LOAD_LIBNAME SetCurrentPath( GetProgramPath() ); hModule = LoadFunction( libname = _WIDE(LOAD_LIBNAME), NULL ); if( !hModule ) { # ifndef UNDER_CE lprintf( WIDE("error: (%")_32fs WIDE(")%s") , GetLastError() , strerror(GetLastError()) ); # endif # ifdef BUILD_SERVICE_THREAD return 0; # else return; # endif } else arg_offset = 0; # else lprintf( WIDE("strerror(This is NOT right... what's the GetStrError?): (%ld)%s") , GetLastError() , strerror(GetLastError()) ); # ifdef BUILD_SERVICE_THREAD return 0; # else return; # endif # endif } { Main = (MainFunction)LoadFunction( libname, WIDE( "_Main" ) ); if( !Main ) Main = (MainFunction)LoadFunction( libname, WIDE( "Main" ) ); if( !Main ) Main = (MainFunction)LoadFunction( libname, WIDE( "Main_" ) ); if( Main ) { // main should be considered windowd.... (no console for output either) Main( my_argc-arg_offset, my_argv+arg_offset, FALSE ); } else { Begin = (BeginFunction)LoadFunction( libname, WIDE( "_Begin" ) ); if( !Begin ) Begin = (BeginFunction)LoadFunction( libname, WIDE( "Begin" ) ); if( !Begin ) Begin = (BeginFunction)LoadFunction( libname, WIDE( "Begin_" ) ); if( Begin ) { int xlen, ofs, arg; for( arg = arg_offset, xlen = 0; arg < my_argc; arg++, xlen += snprintf( NULL, 0, WIDE( "%s%s" ), arg?WIDE( " " ):WIDE( "" ), my_argv[arg] ) ); x = (TEXTCHAR*)malloc( ++xlen ); for( arg = arg_offset, ofs = 0; arg < my_argc; arg++, ofs += snprintf( x + ofs, xlen - ofs, WIDE( "%s%s" ), arg?WIDE( " " ):WIDE( "" ), my_argv[arg] ) ); Begin( x, MODE ); // pass console defined in Makefile free( x ); } else { Start = (StartFunction)LoadFunction( libname, WIDE( "_Start" ) ); if( !Start ) Start = (StartFunction)LoadFunction( libname, WIDE( "Start" ) ); if( !Start ) Start = (StartFunction)LoadFunction( libname, WIDE( "Start_" ) ); if( Start ) { Start( ); } } } } # ifdef BUILD_SERVICE_THREAD return 0; # endif }