Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

255 lines
8.2 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkWin32OutputWindowProcess.c,v $
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#ifdef _MSC_VER
/* Handle MSVC compiler warning messages, etc. */
# pragma warning ( disable : 4115 )
#endif
/* Function to delete executable calling it. */
static int SelfDelete();
#include <windows.h>
#undef _T
#ifdef UNICODE
# define _T(x) L x
#else
# define _T(x) x
#endif
static HWND MainWindow = 0;
static HWND EditWindow = 0;
static LPCTSTR MainWindowClass = _T("vtkOutputWindowProcess");
static LPCTSTR EditWindowClass = _T("EDIT");
static LONG MainWindowStyle = (WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW);
static LONG EditWindowStyle = (ES_MULTILINE | ES_READONLY | WS_CHILD |
ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_VISIBLE |
WS_VSCROLL | WS_HSCROLL | WS_MAXIMIZE);
static LRESULT APIENTRY MainWindowProc(HWND hWnd, UINT m, WPARAM w, LPARAM l)
{
switch (m)
{
case WM_SIZE:
MoveWindow(EditWindow, 0, 0, LOWORD(l), HIWORD(l), TRUE);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd, m, w, l);
}
static void RegisterWindowClass()
{
WNDCLASS wndClass;
if(!GetClassInfo(GetModuleHandle(0), MainWindowClass, &wndClass))
{
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = MainWindowProc;
wndClass.cbClsExtra = 0;
wndClass.hInstance = GetModuleHandle(0);
wndClass.hIcon = LoadIcon(0, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(0, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndClass.lpszMenuName = 0;
wndClass.lpszClassName = MainWindowClass;
wndClass.cbWndExtra = 0;
RegisterClass(&wndClass);
}
}
static DWORD WINAPI ReadThreadProc(LPVOID p)
{
char buffer[1024];
DWORD nRead = 0;
while(ReadFile(GetStdHandle(STD_INPUT_HANDLE), buffer, 1024, &nRead, 0))
{
buffer[nRead] = 0;
SendMessage(EditWindow, EM_SETSEL, (WPARAM)-1, (LPARAM)-1);
SendMessage(EditWindow, EM_REPLACESEL, (WPARAM)0, (LPARAM)buffer);
}
return (DWORD)p;
}
void MainEventLoop()
{
BOOL b;
MSG msg;
while((b = GetMessage(&msg, 0, 0, 0)) != 0 && b != -1)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev,
PSTR szCmdLine, int iCmdShow)
{
(void)hInst; (void)hPrev; (void)szCmdLine; (void)iCmdShow;
/* Setup a child process to delete this executable when it exits. */
SelfDelete();
/* Create a simple GUI. */
RegisterWindowClass();
MainWindow = CreateWindow(MainWindowClass, MainWindowClass, MainWindowStyle,
0,0,512,512, 0, 0, GetModuleHandle(0), 0);
EditWindow = CreateWindow(EditWindowClass, "", EditWindowStyle,
0,0,512,512, MainWindow, 0, GetModuleHandle(0), 0);
ShowWindow(MainWindow, SW_SHOW);
UpdateWindow(MainWindow);
/* Create a thread to read from standard input and write to the window. */
{DWORD threadId; CreateThread(0, 1024, ReadThreadProc, 0, 0, &threadId);}
/* Run the event loop until the window is closed. */
MainEventLoop();
return 0;
}
/*--------------------------------------------------------------------------*/
/* Code to delete executable calling it. Based on code from James
Brown at http://www.catch22.org.uk/tuts/selfdel.asp. */
#pragma pack(push, 1)
#define SELF_DELETE_CODESIZE 0x200
/* Data to inject into remote process. */
typedef struct SelfDeleteRemoteCode_s SelfDeleteRemoteCode;
typedef struct SelfDeleteRemoteCode_s
{
SelfDeleteRemoteCode *Arg0;
BYTE opCodes[SELF_DELETE_CODESIZE];
HANDLE hParent;
DWORD (__stdcall *fnWaitForSingleObject)(HANDLE hHandle, DWORD dwMilliseconds);
BOOL (__stdcall *fnCloseHandle)(HANDLE hObject);
BOOL (__stdcall *fnDeleteFile)(LPCTSTR lpFileName);
void (__stdcall *fnSleep)(DWORD dwMilliseconds);
void (__stdcall *fnExitProcess)(UINT uExitCode);
DWORD (__stdcall *fnGetLastError)(void);
TCHAR szFileName[MAX_PATH];
} SelfDeleteRemoteCode;
#pragma pack(pop)
#ifdef _DEBUG
# error "vtkWin32OutputWindowProcess must be compiled Release"
#endif
/* Function to execute in remote process. It may only call windows
kernel functions through pointers in the SelfDeleteRemoteCode
structure. */
static void SelfDeleteRemoteThread(SelfDeleteRemoteCode* remote)
{
/* Block until parent process terminates. */
remote->fnWaitForSingleObject(remote->hParent, INFINITE);
remote->fnCloseHandle(remote->hParent);
/* Delete the executable file. */
while(!remote->fnDeleteFile(remote->szFileName))
{
remote->fnSleep(1000);
}
/* Exit so that we do not execute garbage code. */
remote->fnExitProcess(0);
}
/* Function to setup remote process that waits for this process to
exit and then deletes its executable. */
static int SelfDelete()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
/* Create a process using the explorer executable but suspend it
immediately. */
if(CreateProcess(0, _T("explorer.exe"), 0, 0, 0,
(CREATE_SUSPENDED | IDLE_PRIORITY_CLASS),
0, 0, &si, &pi))
{
/* Structure to store code and data to copy to remote process. */
SelfDeleteRemoteCode code;
DWORD oldProtect;
CONTEXT context;
DWORD entryPoint;
/* Setup pointers to kernel functions for the remote code to call. */
code.fnWaitForSingleObject = WaitForSingleObject;
code.fnCloseHandle = CloseHandle;
code.fnDeleteFile = DeleteFile;
code.fnSleep = Sleep;
code.fnExitProcess = ExitProcess;
code.fnGetLastError = GetLastError;
/* Give the remote process a copy of our own process handle. */
DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
pi.hProcess, &code.hParent, 0, FALSE, 0);
/* Store the file name of this process's executable. */
GetModuleFileName(0, code.szFileName, MAX_PATH);
/* Store the binary code to execute remotely. */
memcpy(code.opCodes, SelfDeleteRemoteThread, SELF_DELETE_CODESIZE);
/* Allocate some space on process's stack and place our
SelfDeleteRemoteCode structure there. Then set the instruction
pointer to this location and let the process resume. */
context.ContextFlags = (CONTEXT_INTEGER | CONTEXT_CONTROL);
GetThreadContext(pi.hThread, &context);
/* Allocate space on stack that is aligned to cache-line boundary. */
entryPoint = (context.Esp - sizeof(SelfDeleteRemoteCode)) & ~0x1F;
/* Place a pointer to the structure at the bottom-of-stack. This
pointer is located in such a way that it becomes the
SelfDeleteRemoteThread's first argument. */
code.Arg0 = (SelfDeleteRemoteCode*)entryPoint;
/* Set dummy return address for remote thread. It will never return. */
context.Esp = entryPoint - 4;
/* Set remote thread to execute the opCodes we copy to the process. */
context.Eip = entryPoint + (((char*)&code.opCodes) - ((char*)&code));
/* Copy the code and data to the remote process entry point. */
VirtualProtectEx(pi.hProcess, (PVOID)entryPoint, sizeof(code),
PAGE_EXECUTE_READWRITE, &oldProtect);
WriteProcessMemory(pi.hProcess, (PVOID)entryPoint, &code, sizeof(code), 0);
/* Make sure the new code will be loaded. */
FlushInstructionCache(pi.hProcess, (PVOID)entryPoint, sizeof(code));
/* Set the remote thread to execute at our entry point. */
SetThreadContext(pi.hThread, &context);
/* Let the remote process continue. It will block until this
process exits. */
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 1;
}
return 0;
}