I'm on windows and I want to call a specific function when the program terminates.
For example:
void close_program()
{
/*do stuff*/
printf("Goodbye.\n");
}
I tried atexit() but it only worked on casual and regular exits such as a call to the function exit() or when the main returns a value to the OS.
I found out that HandlerRoutine() seems like a solution as windows sends a CTRL_CLOSE_EVENT value signal to the process closed by the user (either just close button or end task through task manager). The problem is I tried a really basic piece of code and it said 'undefined reference to HandlerRoutine' and that it returned 1.
The piece of code:
#include <stdio.h>
#include <windows.h>
int main()
{
while(1)
{
if(HandlerRoutine(CTRL_CLOSE_EVENT))
{
printf("Program is being terminated...\n");
}
}
return 0;
}
I use MinGW.
Any idea what is the problem might be ?
According to MSDN there is no need for linkage.
HandlerRoutine is the callback function that will be invoked when console will be terminated. It's not the function you have to call but the signature (defined as HANDLER_ROUTINE) of your function (that will be invoked by Windows itself):
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType);
You'll inspect dwCtrlType to check for CTRL_CLOSE_EVENT returning (usually) TRUE. To attach your function and make it called you have to use SetConsoleCtrlHandler() API function, like this:
BOOL YourHandler(DWORD dwCtrlType)
{
if (CTRL_CLOSE_EVENT == dwCtrlType)
{
}
return TRUE;
}
Now you have your function but you instruct Windows to call it:
int main()
{
SetConsoleCtrlHandler((PHANDLER_ROUTINE)YourHandler, TRUE);
// Do your stuff here
return 0;
}
Please note that you can register more than one handler, they'll be called in chain up to the one that returns TRUE. For a complete example just consult MSDN.
From the MSDN page you linked
HandlerRoutine is a placeholder for the application-defined function name.
What you need to do is create a callback (of PHANDLER_ROUTINE type) and then use SetConsoleCtrlHandler to register this callback.
Try including wincon.h explicitly. I know there are a number of child header files that are automatically included with windows.h but many of these files cannot simply be included by themselves (they are not self-contained), because of dependencies. wincon.h is one such child header file used for console services.
Related
On Windows it opens a console window that I'd like to get rid of. I want another function that is capable, without exception, of all the same things system() can do, but without that nasty command prompt comng up. I'm making an extension for GameMaker: Studio that does everything I need it to on Linux and Mac as they don't append opening a terminal window with system(). But since Windows works a bit differently with that function, I'm really stuck.
I've tried googling all over for solutions like ShellExecute or CreateProcess but neither of those are what I'm looking for. I want to be able to do DOS/Run Commands. A couple small examples
md c:\new_folder\
or
start notepad.exe
Stuff like that while also supporting multiple arguments. I've seen one possibilty is exec() but it replaces the current process, which on Windows there is no fork() function so I'm not sure how to use exec() how I'd like it to work without a fork() equivalent handy. I'd like to also give the user the ability to choose whether to wait for finishing. For example
// waits for notepad to close before going back to initial application.
SomeCustomFunction("notepad.exe", true);
// does not wait for notepad to close before resume.
SomeCustomFunction("notepad.exe", false);
On Linux, I wrote an *.SO library that looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
extern "C"
{
double SomeCustomFunction(char *fname,double wait)
{
if (wait < 1)
{
if (fork() == 0)
{
system(fname);
exit(0);
}
}
else
{
system(fname);
}
return 0;
}
}
It throws two warnings in Code::Blocks, but it compiles fine and works exactly how I want it to when I call the library from my GameMaker: Studio game / program.
Here's my attempt at the "Windows equivalent" (*.DLL):
#include "main.h"
#define DLL extern "C" _declspec(dllexport)
DLL double SomeCustomFunction(char *fname,double wait)
{
PROCESS_INFORMATION ProcessInfo;
STARTUPINFO StartupInfo;
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof StartupInfo;
if (CreateProcess(NULL, fname,
NULL,NULL,FALSE,0,NULL,
NULL,&StartupInfo,&ProcessInfo))
{
if (wait >=1)
{
WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
}
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
}
return 0;
}
The problem is, on Windows, with the way I have it set up, it doesn't accept the same kind of stuff I'd like it to do, as mentioned earlier in this post.
I would use something like spawn() instead of CreateProcess(), but spawn() requires a separate string and argument for the filename and arguments, which I'd prefer to be all in one string / argument like in my Linux library function.
Thanks
I'll walk you through step by step
First I edit 3 files in my Linux kernel directory
Open LINUX_DIRECTORY/arch/x86/syscalls/syscall_64.tbl and add the custom calls i'm implementing – using the appropriate format
Declare them here: LINUX_DIRECTORY/include/linux/syscalls.h – using the appropriate format:
Open LINUX_DIRECTORY/Makefile and add the directory I'm storing my new system calls to the core-y line:
core-y := usr/ my_system_call_directory/
Here's where I'm having issues. Inside LINUX_DIRECTORY/my_system_call_directory I add a C file with my custom system call definitions and its corresponding Makefile. I leave the definitions empty because inside the C file for my kernel module I declare an extern function (my custom system call) and define a separate function which is set to my extern function:
extern long (*start_shuttle)(void);
long my_start_shuttle(void) {
// stuff here
}
int init_module(void) {
// stuff here
start_shuttle = my_start_shuttle;
// more stuff
}
After recompiling the kernel I try to make the kernel module and get a no definition for start_shuttle error.
Is this because I left the definition for start_shuttle blank in my_system_call_directory? Should it match exactly the my_start_shuttle I defined in the kernel module or is there something special I'm supposed to add? I'm asking dumb questions in advance because it takes so long for my machine to recompile Linux and I'm not sure what to change. Thanks
Figured it out. For anyone as slow as me, you have to use a wrapper and a stub.
So for this example, in the my_system_call_directory, in the c file for your new system call definitions, you need something like this:
#include <linux/linkage.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/export.h>
// initialize the stub function to be NULL
long (*start_shuttle)(void) = NULL;
EXPORT_SYMBOL(start_shuttle);
// wrapper
asmlinkage long sys_start_shuttle(void)
{
if (start_shuttle)
return start_shuttle();
else
return -ENOSYS;
}
I have a sandboxed Cocoa app that, during an export process, needs to run a third party command-line tool. This tool appears to be hardcoded to use /tmp for its temporary files; sandboxing doesn't permit access to this folder, so the export fails.
How can I get this tool to run? I don't have access to its source code, so I can't modify it to use NSTemporaryDirectory(), and it doesn't appear to respect the TMP or TEMPDIR environment variables. For reasons I don't understand, giving myself a com.apple.security.temporary-exception.files.absolute-path.read-write entitlement doesn't seem to work, either.
Is there some way to re-map folders within my sandbox? Is there some obscure trick I can use? Should I try to patch the tool's binary somehow? I'm at my wit's end here.
I was able to get user3159253's DYLD_INSERT_LIBRARIES approach to work. I'm hoping they will write an answer describing how that works, so I'll leave the details of that out and explain the parts that ended up being specific to this case.
Thanks to LLDB, elbow grease, and not a little help from Hopper, I was able to determine that the third-party tool used mkstemp() to generate its temporary file names, and some calls (not all) used a fixed template starting with /tmp. I then wrote a libtmphack.dylib that intercepted calls to mkstemp() and modified the parameters before calling the standard library version.
Since mkstemp() takes a pointer to a preallocated buffer, I didn't feel like I could rewrite a path starting with a short string like "/tmp" to the very long string needed to get to the Caches folder inside the sandbox. Instead, I opted to create a symlink to it called "$tmp" in the current working directory. This could break if the tool chdir()'d at an inopportune time, but fortunately it doesn't seem to do that.
Here's my code:
//
// libtmphack.c
// Typesetter
//
// Created by Brent Royal-Gordon on 8/27/14.
// Copyright (c) 2014 Groundbreaking Software. This file is MIT licensed.
//
#include "libtmphack.h"
#include <dlfcn.h>
#include <stdlib.h>
#include <unistd.h>
//#include <errno.h>
#include <string.h>
static int gbs_has_prefix(char * needle, char * haystack) {
return strncmp(needle, haystack, strlen(needle)) == 0;
}
int mkstemp(char *template) {
static int (*original_mkstemp)(char * template) = NULL;
if(!original_mkstemp) {
original_mkstemp = dlsym(RTLD_NEXT, "mkstemp");
}
if(gbs_has_prefix("/tmp", template)) {
printf("libtmphack: rewrote mkstemp(\"%s\") ", template);
template[0] = '$';
printf("to mkstemp(\"%s\")\n", template);
// If this isn't successful, we'll presume it's because it's already been made
symlink(getenv("TEMP"), "$tmp");
int ret = original_mkstemp(template);
// Can't do this, the caller needs to be able to open the file
// int retErrno = errno;
// unlink("$tmp");
// errno = retErrno;
return ret;
}
else {
printf("libtmphack: OK with mkstemp(\"%s\")\n", template);
return original_mkstemp(template);
}
}
Very quick and dirty, but it works like a charm.
Since #BrentRoyal-Gordon has already published a working solution I'm simply duplicating my comment which inspired him to produce the solution:
In order to fix a program behavior, I would intercept and override some system calls with the help of DYLD_INSERT_LIBRARIES and a custom shared library with a custom implementation of the given system calls.
The exact list of the syscalls which need to be overridden depends on nature of the application and can be studied with a number of tools built upon MacOS DTrace kernel facility. E.g. dtruss or Hopper. #BrentRoyal-Gordon has investigated that the app can be fixed solely with an /appropriate/ implementation of mkstemp.
That's it. I'm still not sure that I've deserved the bounty :)
Another solution would be to use chroot within the child process (or posix_spawn options) to change its root directory to a directory that is within your sandbox. Its “/tmp” will then be a “tmp” directory within that directory.
Assume that we want to intercept the exit system call and print a message on the console when any process invokes it. In order to do this, we have to write our own fake exit system call, then make the kernel call our fake exit function instead of the original exit call. At the end of our fake exit call, we can invoke the original exit call. In order to do this, we must manipulate the system call table array (sys_call_table).
Armed with the sys_call_table array, we can manipulate it to make the sys_exit entry point to our new fake exit call. We must store a pointer to the original sys_exit call and call it when we are done printing our message to the console. Source code :
#include <linux/kernel.h>
#include <linux/module.h>
#include <sys/syscall.h>
extern void *sys_call_table[];
asmlinkage int (*original_sys_exit)(int);
asmlinkage int our_fake_exit_function(int error_code)
{
/*print message on console every time we
*are called*/
printk("HEY! sys_exit called with error_code=%d\n",error_code);
/*call the original sys_exit*/
return original_sys_exit(error_code);
}
/*this function is called when the module is
*loaded (initialization)*/
int init_module()
{
/*store reference to the original sys_exit*/
original_sys_exit=sys_call_table[__NR_exit];
/*manipulate sys_call_table to call our
*fake exit function instead
*of sys_exit*/
sys_call_table[__NR_exit]=our_fake_exit_function;
}
/*this function is called when the module is
*unloaded*/
void cleanup_module()
{
/*make __NR_exit point to the original
*sys_exit when our module
*is unloaded*/
sys_call_table[__NR_exit]=original_sys_exit;
}
When I compile this program I got warning :
WARNING: "sys_call_table" [/home/roiht/driver/one.ko] undefined!
As I did search, I found that kernel version after 2.5 changed the concept of sys_call table.
So, my question is what is alternative method to do this in new kernel version ?
Any kernel variable can be used in a module if it has been explicitly exported in the kernel using EXPORT_SYMBOL(). Since kernel version 2.6, export for sys_call_table has been removed. So if you want to use this approach, explicitly export the variable. As a convention, theis export is done right after the variable declaration, but I guess exporting from any file where this variable is defined will also do. To check if the approach worked, simply look in the output of "cat /proc/kallsyms".
Another approach to capture the exit syscall will be to put a hook in the sysenter part of syscall execution. Look here for more details: http://articles.manugarg.com/systemcallinlinux2_6.html
You can read the address of sys_call_table from System.map-xxx file corresponding to your kernel. The file is usually in /boot directory, and the name is System.map-<kernel-version>, where kernel-version is the result of command uname -r. You can use module parameter to pass the address to your module.
My program loads several dlls and calls their functions. The dlls can use different versions of CRT.
When C runtime checks the validity of arguments and finds problems, it calls the invalid parameter handle, which in turn, closes the application, with or without the "Send-Don't send" dialog.
I tried calling *_set_invalid_parameter_handler* but it only works if it is called from within the bad dll. I tried SetErrorMode, but all I managed to do is get the process killed without the dialog.
Is there any way to handle those exceptions? I don't care if some resources are compromised. All I want is to allow users to save the configuration. If the dialog appears, they click on it and kill the process.
EDIT
It turns out the solution to load all versions of CRT or to enumerate all DLLs fails. To make all clear, here is a small example to play with:
This would be my main application (let's call the file application.c):
#include <windows.h>
void myInvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved) {
wprintf(L"Invalid parameter detected in function %s. File: %s Line: %d\n", function, file, line);
wprintf(L"Expression: %s\n", expression);
}
void fixMyProblem() {
}
int main(int argc, char **argv) {
HMODULE hModule = LoadLibrary("extension.dll");
void (WINAPI *function)() = GetProcAddress(hModule, "function");
fixMyProblem();
function();
}
This application loads a dll that does bad things (it is not developed by me, so I will not accept any solution telling me to fix the bugs there). Lets' call that file extension.c.
#include <stdio.h>
__declspec(dllexport) void function() {
printf("do bad stuff");
fopen(NULL, "r");
}
To compile, do:
cl extension.c /link /OUT:extension.dll /DLL
cl application.c
The question is what do I do in function fixMyProblem(), so that I don't get the send/don't send dialog on XP or the application has stopped working dialog on 7.
According to David Gladfelter I should do
void fixMyProblem() {
_set_invalid_parameter_handler(myInvalidParameterHandler);
}
and also do this for each version CRT available. It turns out that even with one single version of CRT (I use the same for both exe and dll), it still does not work. They both use the same version of CRT, but is seems they do not use the same CRT.
If this is is the case, I assume that the stuff I have to change is inside the DLL. Of course, it does not export *_set_invalid_parameter_handler*.
But to be fair to David Heffernan, here is the implementation for his solution:
#include <Psapi.h>
#pragma comment(lib, "Psapi.lib")
void fixMyProblem() {
HANDLE hProcess = GetCurrentProcess();
HMODULE *hModules;
DWORD requiredSize = 0;
DWORD secondRequiredSize = 0;
if (!EnumProcessModules(hProcess, NULL, 0, &requiredSize)) {
printf("oops\n");
return;
}
hModules = malloc(requiredSize);
if (EnumProcessModules(hProcess, hModules, requiredSize, &secondRequiredSize)) {
int i;
int loadedModules = min(requiredSize, secondRequiredSize) / sizeof(HMODULE);
for (i = 0; i < loadedModules; i++) {
void *(WINAPI *_set_invalid_parameter_handler_function)(void *) = (void *(WINAPI *)(void *)) GetProcAddress(hModules[i], "_set_invalid_parameter_handler");
if (_set_invalid_parameter_handler_function != NULL) {
_set_invalid_parameter_handler_function(myInvalidParameterHandler);
printf("fixed dll %d\n", i);
}
}
} else {
printf("oops\n");
}
free(hModules);
}
For my real application, not this test, I get 1 dll fixed (msvcp90.dll). It still does not fix my problem.
I would appreciate any help in solving this.
If the dll is built with a statically linked CRT, then the state and functions of the CRT will be local to that instance of the dll.
I am assuming the invalid parameter handler used by the CRT is calling the UnhandledExceptionFilter function, from the OS, to show that "nice" error dialog.
You could try to hook functions like UnhandledExceptionFilter or TerminateProcess, making the dll use your own functions instead. You can do this by parsing the Import Address Table of the loaded dll, search for the function name you are interested, and change the address to point to your function.
You could always enumerate the modules in your process and if it's a C runtime then get hold of the invalid parameter handler with a call to GetProcAddress.
But you'd be better off trying to fix the bugs at root. Trying to ignore such problems mostly just leads to further problems because memory gets corrupted and so on.
You could create another DLL that uses the same version of the CRT as the version used by the DLL that causes the invalid parameter handler to be called and register the invalid parameter handler it in that new DLL. The invalid parameter handler is global to the process/CRT-version combination.
If you don't know what version the DLL is using and you can't figure it out, worst-case is you create several DLL's, one for each CRT version:
VS 6 static/dynamic/multithreaded/single-threaded
VS.NET static/dynamic/multithreaded/single-threaded
VS 2003 static/dynamic/multithreaded/single-threaded
VS 2005 static/dynamic
VS 2008 static/dynamic
VS 2010 static/dynamic
You could probably create them as static .lib files and link them all into one (very confused) DLL.