Using multiple threads with GTK? - c

How do I use multiple threads in GTK? I have 2 threads, one initializes the GUI and then continuously runs gtk_main() to draw my gui and my other thread does all my program logic and computing, however when my program logic thread updates a GtkImage it will randomly and inconsistently stop updating and freeze and will not draw the anything on the form anymore.
I have read and been told to only call GTK functions from the gtk thread but that is impossible as once you call gtk_main() it will be stuck there until the program exits.
Anyone know how I can get my program and gui cooperating together and show me an example of how it would work with my existing program?
I have been stuck on this for hours now and need to finish this script for a company soon so they can use it to help automate one of their tasks at their manufacturing facility.
Ex.
static GtkWidget* gtk_image;
void my_thread()
{
while (1) {
//wait for input
//do program logic
//update gtk_image to new image
}
}
void gui_thread() {
//initialize gui
//call gtk_main //it never exits this function until program is closed so you can see how its impossible to make any drawing calls from this thread
}
my actual code looks like this (where cam_main and main_gtk are the threads I was mentioning):
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdarg.h>
#include <gphoto2/gphoto2-camera.h>
#include <gphoto2/gphoto2-context.h>
#include <wiringPi.h>
#include <gtk/gtk.h>
#include <pthread.h>
//program
static int running = 1;
//libgphoto2
static CameraList* list;
static Camera** cams;
static GPContext* context;
static const char *name, *value;
static int ret, count;
static int pic = 0;
static int front = 1;
static const char* workingDir;
//GTK
static GtkWidget *window, *vbox,*hboxDir, *hboxCamLabels, *hboxFrontPics, *hboxBackPics, *hboxStatus, *lblDir, *btnConfigDir, *lblCams, *lblFront, *lblBack, *lblCurrentStatus;
static GtkWidget *front_cams[3];
static GtkWidget *back_cams[3];
static GdkPixbuf *pxbscaled = NULL;
static GdkPixbuf *pixbuf = NULL;
static GError* err = NULL;
static void btnConfigDir_ConfigureDirectory(GtkWidget* widget, gpointer data) {
GtkWidget *dialog;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
gint res;
dialog = gtk_file_chooser_dialog_new ("Open File", window,
action,
"_Cancel",
GTK_RESPONSE_CANCEL,
"_Open",
GTK_RESPONSE_ACCEPT,
NULL);
res = gtk_dialog_run (GTK_DIALOG (dialog));
if (res == GTK_RESPONSE_ACCEPT)
{
char *filename;
GtkFileChooser *chooser = GTK_FILE_CHOOSER (dialog);
workingDir = gtk_file_chooser_get_filename (chooser);
}
//gtk_label_set_text((GTK_LABEL)lblDir, workingDir);
gtk_widget_destroy (dialog);
}
void* main_gtk() {
//GTK WIDGET QUEUE REDRAW WOULD REDRAW AT APPROPRIATE TIME
//INIT GTK
gtk_init(NULL, NULL);
//SETUP WINDOW
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
//button1=gtk_button_new_with_label("Click me");
//gtk_button_set_label(GTK_BUTTON(button1), "click me 1");
g_signal_connect(window,"delete-event", G_CALLBACK(gtk_main_quit), NULL);
workingDir = "/media/pi/SD CARD";
lblDir = gtk_label_new("Save to: dir\t");
btnConfigDir = gtk_button_new_with_label("Configure Directory");
g_signal_connect(btnConfigDir, "clicked", G_CALLBACK(btnConfigDir_ConfigureDirectory), NULL);
lblCams = gtk_label_new("\t\t\t\t\t\t\t\tCAM 1\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tCAM2\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tCAM3");
lblFront = gtk_label_new("Front");
lblBack = gtk_label_new("Back ");
lblCurrentStatus = gtk_label_new("Current Status: Idle");
//SET WINDOW SIZE AND TITLE
//gtk_widget_set_size_request(window, 600, 400);
gtk_window_set_title(GTK_WINDOW(window), "CaptureGui");
//RESIZE IMAGES
//image
front_cams[0] = gtk_image_new();
front_cams[1] = gtk_image_new();
front_cams[2] = gtk_image_new();
back_cams[0] = gtk_image_new();
back_cams[1] = gtk_image_new();
back_cams[2] = gtk_image_new();
GdkPixbuf* pxb;
pxb = gdk_pixbuf_new(0, 0, 8, 500, 300);
gtk_image_set_from_pixbuf(GTK_IMAGE(front_cams[0]), pxb);
gtk_image_set_from_pixbuf(GTK_IMAGE(front_cams[1]), pxb);
gtk_image_set_from_pixbuf(GTK_IMAGE(front_cams[2]), pxb);
gtk_image_set_from_pixbuf(GTK_IMAGE(back_cams[0]), pxb);
gtk_image_set_from_pixbuf(GTK_IMAGE(back_cams[1]), pxb);
gtk_image_set_from_pixbuf(GTK_IMAGE(back_cams[2]), pxb);
//g_print("1");
//front_cams[0] = gtk_image_new_from_file("/media/pi/SD CARD/cam-1_0_a_front.jpg");
//set_image_scaled(front_cams[0], "/media/pi/SD CARD/cam-1_1_a_front.jpg");
//set_image_scaled(front_cams[1], "/media/pi/SD CARD/cam-1_1_a_front.jpg");
//set_image_scaled(front_cams[2], "/media/pi/SD CARD/cam-1_1_b_back.jpg");
//PACK
hboxDir = gtk_box_new(0, 0);
hboxCamLabels = gtk_box_new(0, 0);
hboxFrontPics = gtk_box_new(0, 0);
hboxBackPics = gtk_box_new(0, 0);
hboxStatus = gtk_box_new(0, 0);
vbox = gtk_vbox_new(0, 10);
gtk_box_pack_end(GTK_BOX(hboxDir), btnConfigDir, 0, 0, 0);
gtk_box_pack_end(GTK_BOX(hboxDir), lblDir, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hboxCamLabels), lblCams, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hboxFrontPics), lblFront, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hboxFrontPics), front_cams[0], 0, 0, 10);
gtk_box_pack_start(GTK_BOX(hboxFrontPics), front_cams[1], 0, 0, 10);
gtk_box_pack_start(GTK_BOX(hboxFrontPics), front_cams[2], 0, 0, 10);
gtk_box_pack_start(GTK_BOX(hboxBackPics), lblBack, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hboxBackPics), back_cams[0], 0, 0, 10);
gtk_box_pack_start(GTK_BOX(hboxBackPics), back_cams[1], 0, 0, 10);
gtk_box_pack_start(GTK_BOX(hboxBackPics), back_cams[2], 0, 0, 10);
gtk_box_pack_start(GTK_BOX(hboxStatus), lblCurrentStatus, 0, 0, 10);
gtk_box_pack_start(GTK_BOX(vbox), hboxDir, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), hboxCamLabels, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), hboxFrontPics, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), hboxBackPics, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), hboxStatus, 0, 0, 0);
//gtk_box_pack_start(GTK_BOX(hbox), front_cams[0], 0, 0, 0);
//gtk_box_pack_start(GTK_BOX(hbox), front_cams[1], 0, 0, 0);
//gtk_box_pack_start(GTK_BOX(hbox), front_cams[2], 0, 0, 0);
//gtk_box_pack_start(GTK_BOX(hbox), back_cams[0], 0, 0, 0);
//gtk_box_pack_start(GTK_BOX(hbox), back_cams[1], 0, 0, 0);
//gtk_box_pack_start(GTK_BOX(hbox), back_cams[2], 0, 0, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
//ADD ELEMENTS TO GUI
//gtk_container_add(GTK_CONTAINER(window), image1);
//gtk_container_add(GTK_CONTAINER(window), image2);
//image2 = gtk_image_new_from_file("/media/pi/SD CARD/cam-1_0_b_back.jpg");
//gtk_container_add(GTK_CONTAINER(window), image2);
//SHOW GUI
gtk_widget_show_all(window);
gtk_main();
}
void set_image_scaled(GtkWidget* img, const char* path) {
pixbuf = gdk_pixbuf_new_from_file(path, &err);
g_assert_no_error(err);
pxbscaled = gdk_pixbuf_scale_simple(pixbuf, 500, 300, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(img), pxbscaled);
g_object_unref(pixbuf);
g_object_unref(pxbscaled);
}
void* cam_main() {
while (running == 1) {
if (digitalRead(4) == 0)
{
printf("taking pics of %s item %i\n", (front == 1) ? "front" : "back", pic);
for (int i = 0; i < count; i++)
{
int fd, retval;
CameraFile *file;
CameraFilePath cfPath;
strcpy(cfPath.folder, "/");
strcpy(cfPath.name, "foo1.jpg");
printf("Capturing cam%i...\n", i + 1);
int res = gp_camera_capture(cams[i], GP_CAPTURE_IMAGE, &cfPath, context);
//printf(gp_port_result_as_string(res));
printf("capture result: %i\n", res);
//Camera won't take pic if busy and will continue to program end
char buf[256];
snprintf(buf, sizeof(buf), "%s/cam-%i_%i_%s.jpg", workingDir, i + 1, pic, (front == 1) ? "a_front" : "b_back"); //a_ to make front come before back otherwise systems will order incorrectly
fd = open(buf, O_CREAT | O_WRONLY, 0644);
retval = gp_file_new_from_fd(&file, fd);
retval = gp_camera_file_get(cams[i], cfPath.folder, cfPath.name, GP_FILE_TYPE_NORMAL, file, context);
retval = gp_camera_file_delete(cams[i], cfPath.folder, cfPath.name, context);
gp_file_free(file);
//debug
//if (front == 1 && i == 0)
// set_image_scaled(front_cams[0], buf);
if (front == 1)
set_image_scaled(front_cams[i], buf);
else
set_image_scaled(back_cams[i], buf);
}
if (front == 1)
front = 0;
else
{
front = 1;
pic += 1;
}
printf("pics taken...\n");
}
}
}
int main(int argc, char **argv)
{
//Kill any processes using cams
system("pkill -f gphoto2");
//Wiring pi init
wiringPiSetupGpio();
//Init
context = gp_context_new();
detect_cams();
pthread_t logic_thread_handle, gui_thread_handle;
pthread_create(&logic_thread_handle, NULL, cam_main, NULL);
pthread_create(&gui_thread_handle, NULL, main_gtk, NULL);
pthread_join(gui_thread_handle, 0);
pthread_join(logic_thread_handle, 0);
//Deinit
for (int i = 0; i < count; i++)
{
gp_camera_exit(cams[i], context);
gp_camera_free(cams[i]);
}
return 0;
}
void detect_cams() {
//Detecting all cameras and loading them into mem
//Detecting all cameras
ret = gp_list_new(&list);
if (ret < GP_OK) return 1;
gp_list_reset(list);
count = gp_camera_autodetect(list, context);
if (count < 1)
{
printf("No cameras detected.\n");
return 1;
}
//Open all cameras
printf("Number of cameras: %d\n", count);
cams = calloc(sizeof (Camera*), count);
for (int i = 0; i < count; i++)
{
gp_list_get_name(list, i, &name);
gp_list_get_value(list, i, &value);
ret = open_cam(&cams[i], name, value, context);
if (ret < GP_OK)
fprintf(stderr, "Camera %s on port %s failed to open\n", name, value);
}
}
int open_cam(Camera ** camera, const char *model, const char *port, GPContext *context) {
GPPortInfoList *portinfolist = NULL;
CameraAbilitiesList *abilities = NULL;
int ret, m, p;
CameraAbilities a;
GPPortInfo pi;
ret = gp_camera_new (camera);
if (ret < GP_OK) return ret;
if (!abilities) {
/* Load all the camera drivers we have... */
ret = gp_abilities_list_new (&abilities);
if (ret < GP_OK) return ret;
ret = gp_abilities_list_load (abilities, context);
if (ret < GP_OK) return ret;
}
/* First lookup the model / driver */
m = gp_abilities_list_lookup_model (abilities, model);
if (m < GP_OK) return ret;
ret = gp_abilities_list_get_abilities (abilities, m, &a);
if (ret < GP_OK) return ret;
ret = gp_camera_set_abilities (*camera, a);
if (ret < GP_OK) return ret;
if (!portinfolist) {
/* Load all the port drivers we have... */
ret = gp_port_info_list_new (&portinfolist);
if (ret < GP_OK) return ret;
ret = gp_port_info_list_load (portinfolist);
if (ret < 0) return ret;
ret = gp_port_info_list_count (portinfolist);
if (ret < 0) return ret;
}
/* Then associate the camera with the specified port */
p = gp_port_info_list_lookup_path (portinfolist, port);
switch (p) {
case GP_ERROR_UNKNOWN_PORT:
fprintf (stderr, "The port you specified "
"('%s') can not be found. Please "
"specify one of the ports found by "
"'gphoto2 --list-ports' and make "
"sure the spelling is correct "
"(i.e. with prefix 'serial:' or 'usb:').",
port);
break;
default:
break;
}
if (p < GP_OK) return p;
ret = gp_port_info_list_get_info (portinfolist, p, &pi);
if (ret < GP_OK) return ret;
ret = gp_camera_set_port_info (*camera, pi);
if (ret < GP_OK) return ret;
return GP_OK;
}

I have read and been told to only call GTK functions from the gtk thread but that is impossible as once you call gtk_main() it will be stuck there until the program exits.
No, it's not impossible. Control is returned to your program even while gtk_main() is active, by means of callbacks. In your thread, you can schedule a callback to be called in the GTK thread using gdk_threads_add_idle(). See GTK3 and multithreading, replacing deprecated functions for more information.

Related

Setting X11 root window pixmap

The code below is supposed to make root window white, but does nothing. Compiles and runs with no errors. I omitted only includes and variable definitions.
int
main(int argc, char **argv) {
dpy = XOpenDisplay(NULL);
if (!dpy) {
fputs("cannot open display\n", stderr);
return EXIT_FAILURE;
}
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
vis = DefaultVisual(dpy, screen);
depth = DefaultDepth(dpy, screen);
height = DisplayHeight(dpy, screen);
width = DisplayWidth(dpy, screen);
img = malloc(depth/8 * height * width);
if (img == NULL) {
perror("malloc() failed");
return EXIT_FAILURE;
}
memset(img, 0xFF, depth/8 * height * width);
ximg = XCreateImage(dpy, vis, depth, ZPixmap, 0, img, width, height, 32, 0);
pm = XCreatePixmap(dpy, root, width, height, depth);
gc = XCreateGC(dpy, pm, 0, NULL);
XPutImage(dpy, pm, gc, ximg, 0, 0, 0, 0, width, height);
XSetWindowBackgroundPixmap(dpy, root, pm);
XClearWindow(dpy, root);
XFlush(dpy);
XDestroyImage(ximg);
XFreePixmap(dpy, pm);
XFreeGC(dpy, gc);
XCloseDisplay(dpy);
return EXIT_SUCCESS;
}
How do I even start troubleshooting this? removing XClearWindow(dpy, root); does not help.
Apparently XSetWindowBackgroundPixmap() needs some prior atom setup. This borrowed function fixed the issue.
// Adapted from fluxbox' bsetroot
int
setRootAtoms(Pixmap pixmap)
{
Atom atom_root, atom_eroot, type;
unsigned char *data_root, *data_eroot;
int format;
unsigned long length, after;
atom_root = XInternAtom(display, "_XROOTMAP_ID", True);
atom_eroot = XInternAtom(display, "ESETROOT_PMAP_ID", True);
// doing this to clean up after old background
if (atom_root != None && atom_eroot != None) {
XGetWindowProperty(display, RootWindow(display, screen), atom_root, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data_root);
if (type == XA_PIXMAP) {
XGetWindowProperty(display, RootWindow(display, screen), atom_eroot, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data_eroot);
if (data_root && data_eroot && type == XA_PIXMAP && *((Pixmap *) data_root) == *((Pixmap *) data_eroot))
XKillClient(display, *((Pixmap *) data_root));
}
}
atom_root = XInternAtom(display, "_XROOTPMAP_ID", False);
atom_eroot = XInternAtom(display, "ESETROOT_PMAP_ID", False);
if (atom_root == None || atom_eroot == None)
return 0;
// setting new background atoms
XChangeProperty(display, RootWindow(display, screen), atom_root, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &pixmap, 1);
XChangeProperty(display, RootWindow(display, screen), atom_eroot, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &pixmap, 1);
return 1;
}

How to resize/rescale an image loaded into microsoft visual studio 2019 using the win32 library?

I have an image to load into my GUI, using the win32 library. It's too large and so the entire image does not get displayed.
Below is the code for the window and painting the image onto the window.
The target image is 1600 pixels wide and 1140 pixels tall.
LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
HMENU hMenu;
OPENFILENAME ofn;
FILE *fpt;
HDC hDC;
char header[320],text[320];
int BYTES,xPos,yPos;
switch (uMsg)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_FILE_CLEARIMAGE:
//Clear image
PaintImage();
break;
case ID_FILE_LOAD:
if (OriginalImage != NULL || image_loaded == 1)
{
for (int i = 0; i < 1500; i++)
{
for (int j = 0; j < 1500; j++)
{
OriginalImage[i * COLS + j] = 255;
}
}
OriginalImage = NULL;
free(OriginalImage);
}
memset(&(ofn),0,sizeof(ofn));
ofn.lStructSize=sizeof(ofn);
ofn.lpstrFile=filename;
filename[0]=0;
ofn.nMaxFile=MAX_FILENAME_CHARS;
ofn.Flags=OFN_EXPLORER | OFN_HIDEREADONLY;
ofn.lpstrFilter = "PNM files\0*.pnm\0All files\0*.*\0\0";
if (!( GetOpenFileName(&ofn)) || filename[0] == '\0')
break; /* user cancelled load */
if ((fpt=fopen(filename,"rb")) == NULL)
{
MessageBox(NULL,"Unable to open file",filename,MB_OK | MB_APPLMODAL);
break;
}
fscanf(fpt,"%s\n%d %d\n%d",header,&COLS,&ROWS,&BYTES);
if (strcmp(header,"P6") != 0 || BYTES != 255)
{
MessageBox(NULL,"Not a PNM image",filename,MB_OK | MB_APPLMODAL);
fclose(fpt);
break;
}
OriginalImage=(unsigned char *)calloc(ROWS*COLS*3,1);
header[0]=fgetc(fpt); /* whitespace character after header */
fread(OriginalImage,1,ROWS*COLS*3,fpt);
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
OriginalImage[i * COLS + j] = (int)(OriginalImage[i * (COLS * 3) + (j * 3)] +
OriginalImage[i * (COLS * 3) + (j * 3) + 1] +
OriginalImage[i * (COLS * 3) + (j * 3) + 2])/3.0;
}
}
image_loaded = 1;
fclose(fpt);
SetWindowText(hWnd,filename);
PaintImage();
break;
case ID_FILE_QUIT:
DestroyWindow(hWnd);
break;
}
break;
case WM_SIZE: /* could be used to detect when window size changes */
PaintImage();
return(DefWindowProc(hWnd,uMsg,wParam,lParam));
break;
case WM_PAINT:
PaintImage();
return(DefWindowProc(hWnd,uMsg,wParam,lParam));
break;
Below is the paint function
void PaintImage()
{
PAINTSTRUCT Painter;
HDC hDC;
BITMAPINFOHEADER bm_info_header;
BITMAPINFO *bm_info;
int i,r,c,DISPLAY_ROWS,DISPLAY_COLS;
unsigned char *DisplayImage;
HDC hdcScaled;
HBITMAP hbmScaled;
if (OriginalImage == NULL)
return; /* no image to draw */
/* Windows pads to 4-byte boundaries. We have to round the size up to 4 in each dimension, filling with black. */
DISPLAY_ROWS=ROWS;
DISPLAY_COLS=COLS;
if (DISPLAY_ROWS % 4 != 0)
DISPLAY_ROWS=(DISPLAY_ROWS/4+1)*4;
if (DISPLAY_COLS % 4 != 0)
DISPLAY_COLS=(DISPLAY_COLS/4+1)*4;
DisplayImage=(unsigned char *)calloc(DISPLAY_ROWS*DISPLAY_COLS,1);
for (r=0; r<ROWS; r++)
for (c=0; c<COLS; c++)
DisplayImage[r*DISPLAY_COLS+c] = OriginalImage[r*COLS+c];
BeginPaint(MainWnd,&Painter);
hDC=GetDC(MainWnd);
bm_info_header.biSize=sizeof(BITMAPINFOHEADER);
bm_info_header.biWidth=DISPLAY_COLS;
bm_info_header.biHeight=-DISPLAY_ROWS;
bm_info_header.biPlanes=1;
bm_info_header.biBitCount=8;
bm_info_header.biCompression=BI_RGB;
bm_info_header.biSizeImage=0;
bm_info_header.biXPelsPerMeter=0;
bm_info_header.biYPelsPerMeter=0;
bm_info_header.biClrUsed=256;
bm_info_header.biClrImportant=256;
bm_info=(BITMAPINFO *)calloc(1,sizeof(BITMAPINFO) + 256*sizeof(RGBQUAD));
bm_info->bmiHeader=bm_info_header;
for (i=0; i<256; i++)
{
bm_info->bmiColors[i].rgbBlue = bm_info->bmiColors[i].rgbGreen = bm_info->bmiColors[i].rgbRed = i;
bm_info->bmiColors[i].rgbReserved=0;
}
SetDIBitsToDevice(hDC,0,0,DISPLAY_COLS,DISPLAY_ROWS,0,0,
0, /* first scan line */
DISPLAY_ROWS, /* number of scan lines */
DisplayImage,bm_info,DIB_RGB_COLORS);
hdcScaled = CreateCompatibleDC(hDC);
hbmScaled = CreateCompatibleBitmap(hDC, GetDeviceCaps(hDC, HORZRES) * 0.5, GetDeviceCaps(hDC, VERTRES) * 0.5);
ReleaseDC(MainWnd,hDC);
EndPaint(MainWnd,&Painter);
free(DisplayImage);
free(bm_info);
}
The following is a link I found on resizing/rescaling images, but I don't understand how to implement it using my code.
C++ WIN32: Rescaling Bitmaps/Giving Bitmaps HDC's
Please advise.
The StretchBlt method is pointed out in the link.
Add the following code in PaintImage(),
void PaintImage()
{
for (i=0; i<256; i++)
{
bm_info->bmiColors[i].rgbBlue = bm_info->bmiColors[i].rgbGreen = bm_info->bmiColors[i].rgbRed = i;
bm_info->bmiColors[i].rgbReserved=0;
}
...
RECT rc;
GetClientRect(MainWnd, &rc);
hdcScaled = CreateCompatibleDC(hDC);
hbmScaled = CreateCompatibleBitmap(hDC, DISPLAY_COLS, DISPLAY_ROWS);
SelectObject(hdcScaled, hbmScaled);
SetDIBitsToDevice(hdcScaled, 0, 0, DISPLAY_COLS, DISPLAY_ROWS, 0, 0,
0, /* first scan line */
DISPLAY_ROWS, /* number of scan lines */
DisplayImage, bm_info, DIB_RGB_COLORS);
SetStretchBltMode(hDC, HALFTONE);
StretchBlt(hDC, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdcScaled, 0, 0, DISPLAY_COLS, DISPLAY_ROWS, SRCCOPY);
DeleteObject(hdcScaled);
DeleteObject(hbmScaled);
...
}
Note: Delete objects to avoid memory leaks
You could use the CAPI library. It has a very easy to use image stretch functions
capi_DrawImageEx
capi_DrawImageExA
Here is a simple example program that demonstrates stretching an image to fit into a window.
#include <Windows.h>
#include <CAPI.h>
#define WinClassName STR("ExampleProgram")
#define WinTitle STR("Example Program")
#ifdef UNICODE
#define app_fopen _wfopen_s
#define app_printf wprintf
#define ApplicationEntryPoint wWinMain
#else
#define app_fopen fopen_s
#define app_printf printf
#define ApplicationEntryPoint WinMain
#endif // UNICODE
static HWND Window_hWnd = 0;
static HDC BufferHDC = 0;
static BITMAPINFO* pDisplayBitmap = 0;
static HBITMAP hBitmap = 0;
static int ClientWidth;
static int ClientHeight;
static IMAGE FrameBuffer;
static IMAGE exampleImage;
void* LoadFile(const STRING* FilePath, U64* pFileSize)
{
FILE* Stream;
size_t BufferLength;
void* pThisFile;
void* pNewBlock;
if ((FilePath == 0) || (pFileSize == 0)) return 0;
*pFileSize = 0;
if (app_fopen(&Stream, FilePath, STR("rb")) != 0) return 0;
if (Stream == 0) return 0;
pThisFile = 0;
BufferLength = 0;
do
{
BufferLength += 0x1000;
pNewBlock = capi_realloc(pThisFile, BufferLength);
if (pNewBlock == 0)
{
if (pThisFile != 0) capi_free(pThisFile);
fclose(Stream);
return 0;
}
pThisFile = pNewBlock;
*pFileSize += fread(&((U8*)pThisFile)[*pFileSize], 1, 0x1000, Stream);
} while (!(feof(Stream)));
fclose(Stream);
return pThisFile;
}
I32 SaveFile(const STRING* FilePath, void* pFilePointer, U64 FileSize)
{
FILE* Stream;
size_t nBytesWrite;
I32 ErrorCode;
if ((FilePath == 0) || (pFilePointer == 0) || (FileSize == 0)) return CAPI_ERROR_INVALID_PARAMETER;
ErrorCode = CAPI_ERROR_NONE;
if (app_fopen(&Stream, FilePath, STR("w+b")) != 0) return CAPI_ERROR_ACCESS_DENIED;
if (Stream == 0) return CAPI_ERROR_ACCESS_DENIED;
nBytesWrite = fwrite(pFilePointer, 1, (size_t)FileSize, Stream);
if (nBytesWrite != FileSize)
{
ErrorCode = CAPI_ERROR_ACCESS_DENIED;
goto exit_func;
}
exit_func:
fclose(Stream);
return ErrorCode;
}
void FreeSysInternal()
{
if (BufferHDC != 0)
{
DeleteDC(BufferHDC);
BufferHDC = 0;
}
if (pDisplayBitmap != 0)
{
capi_free(pDisplayBitmap);
pDisplayBitmap = 0;
}
if (hBitmap != 0)
{
DeleteObject(hBitmap);
hBitmap = 0;
}
}
U32 SetupWindowFrameBuffer(HDC WindowHDC, RECT* ClientRt)
{
FreeSysInternal();
pDisplayBitmap = (BITMAPINFO*)capi_malloc(sizeof(BITMAPINFOHEADER));
if (pDisplayBitmap == 0) return 1;
pDisplayBitmap->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pDisplayBitmap->bmiHeader.biWidth = ClientRt->right;
pDisplayBitmap->bmiHeader.biHeight = -ClientRt->bottom;
pDisplayBitmap->bmiHeader.biPlanes = 1;
pDisplayBitmap->bmiHeader.biBitCount = 32;
pDisplayBitmap->bmiHeader.biCompression = 0;
pDisplayBitmap->bmiHeader.biSizeImage = 0;
pDisplayBitmap->bmiHeader.biXPelsPerMeter = 0;
pDisplayBitmap->bmiHeader.biYPelsPerMeter = 0;
pDisplayBitmap->bmiHeader.biClrUsed = 0;
pDisplayBitmap->bmiHeader.biClrImportant = 0;
BufferHDC = CreateCompatibleDC(WindowHDC);
if (BufferHDC == 0)
{
capi_free(pDisplayBitmap);
return 2;
}
hBitmap = CreateDIBSection(BufferHDC, pDisplayBitmap, 0,
(void**)&FrameBuffer.Pixels, 0, 0);
if (hBitmap == 0)
{
DeleteDC(BufferHDC);
capi_free(pDisplayBitmap);
return 3;
}
GdiFlush();
FrameBuffer.ScanLine = ClientRt->right;
FrameBuffer.Width = ClientRt->right;
FrameBuffer.Height = ClientRt->bottom;
SelectObject(BufferHDC, hBitmap);
return 0;
}
void Window_Paint_Handler(IMAGE* pDisplay)
{
// Fill the background of our window.
capi_FillImage(pDisplay, COLOR(195, 195, 195, 255));
// Now we stretch our test image to the size of the window.
// Note: The last parameter (Alpha) must be 255 for the image to be displayed normally.
capi_DrawImageExA(pDisplay, &exampleImage, 0, 0, DRAW_RESIZE_BOXSAMP, pDisplay->Width, pDisplay->Height, 255);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC WinDC;
PAINTSTRUCT ps;
RECT WinArea;
RECT ClientArea;
int BorderWidth;
int BorderHeight;
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_ERASEBKGND:
return TRUE;
case WM_PAINT:
{
WinDC = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &ClientArea);
if ((ClientArea.right == 0) || (ClientArea.bottom == 0)) goto exit_paint_message;
if ((ClientArea.right != FrameBuffer.Width) || (ClientArea.bottom != FrameBuffer.Height))
{
if (SetupWindowFrameBuffer(WinDC, &ClientArea) != 0) goto exit_paint_message;
}
Window_Paint_Handler(&FrameBuffer);
SetDIBits(BufferHDC, hBitmap, 0,
pDisplayBitmap->bmiHeader.biHeight, FrameBuffer.Pixels, pDisplayBitmap, 0);
BitBlt(WinDC, 0, 0, ClientArea.right, ClientArea.bottom, BufferHDC, 0, 0, 0x00CC0020);
exit_paint_message:
EndPaint(hWnd, &ps);
break;
}
case WM_CREATE:
{
Window_hWnd = hWnd;
GetWindowRect(hWnd, &WinArea);
GetClientRect(hWnd, &ClientArea);
BorderWidth = WinArea.right - ClientArea.right;
BorderHeight = WinArea.bottom - ClientArea.bottom;
SetWindowPos(hWnd, NULL,
0, 0,
BorderWidth + ClientWidth, BorderHeight + ClientHeight, SWP_NOMOVE | SWP_NOZORDER);
GetWindowRect(hWnd, &WinArea);
SetWindowPos(hWnd, NULL,
(GetSystemMetrics(SM_CXSCREEN) - (WinArea.right - WinArea.left)) / 2,
(GetSystemMetrics(SM_CYSCREEN) - (WinArea.bottom - WinArea.top)) / 2,
0, 0, SWP_NOSIZE | SWP_NOZORDER);
break;
}
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
int WINAPI ApplicationEntryPoint(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ STRING* pCmdLine, _In_ int nCmdShow)
{
MSG msg;
WNDCLASSEX wcex;
void* myLoadedFile;
U64 FileSize;
I32 ErrorCode;
// Load our image to draw to the window frame buffer.
myLoadedFile = LoadFile(STR("C:/Users/Public/myTestImage.ico"), &FileSize);
if (myLoadedFile == 0)
{
MessageBox(0, STR("LoadFile Failed."), STR("Error!"), MB_OK);
return 0;
}
ErrorCode = capi_LoadImageFromMemory(&exampleImage, 1, myLoadedFile, FileSize);
if (ErrorCode != CAPI_ERROR_NONE)
{
MessageBox(0, STR("capi_LoadImageFromMemory Failed."), STR("Error!"), MB_OK);
return 0;
}
// The client area of our window will be the same size as our test image.
ClientWidth = exampleImage.Width;
ClientHeight = exampleImage.Height;
// Create the display window and enter the thread/window message loop.
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = WinClassName;
wcex.hIconSm = NULL;
if (!RegisterClassEx(&wcex))
{
MessageBox(0, STR("Failed to register the window class."), STR("Error!"), MB_OK);
return 0;
}
// Note: The 700 (Width) and 500 (Height) values are just dummy values. The Width and Height get set in the WM_CREATE message handler.
CreateWindowEx(0, WinClassName, WinTitle,
WS_VISIBLE | WS_CLIPCHILDREN | WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU | WS_SIZEBOX | WS_MAXIMIZEBOX,
0, 0, 700, 500, NULL, NULL, hInstance, NULL);
if (!Window_hWnd)
{
MessageBox(0, STR("Failed to create the window."), STR("Error!"), MB_OK);
return 0;
}
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
FreeSysInternal();
return 0;
}

What is causing this C memory leak? (exited with error 137)

I'm not too sure why my C program is leaking, it has something to do with the set_image_scaled() function I'm pretty sure and it has to do with me resizing an image. Basically once I take a picture with gphoto2, I save that file to a jpg, then I open that picture in GTK and resize it down with a pixbuf and then set the image widgets on the display accordingly. How can I fix this? I am lost. Been playing around with it for hours now. I am on raspberry pi on raspbian. Model 3b+.
This is the error it gives me:
(guiphoto:2344): GdkPixbuf-CRITICAL **: 13:57:26.656: gdk_pixbuf_scale_simple: assertion 'GDK_IS_PIXBUF (src)' failed
**
ERROR:guiphoto.c:94:set_image_scaled: assertion failed (err == NULL): Failed to load image “/media/pi/SD CARD/cam-1_1_b_back.jpg”: Insufficient memory to open TIFF file (gdk-pixbuf-error-quark, 1)
Aborted
The problematic code that keeps running into a memory leak is in the cam_main function, specifically:
if (front == 1)
set_image_scaled(front_cams[i], buf);
else
set_image_scaled(back_cams[i], buf);
So I believe it has to do with this code right here and the static variables at the top of my program:
void set_image_scaled(GtkWidget* img, const char* path) {
pixbuf = gdk_pixbuf_new_from_file(path, &err);
pxbscaled = gdk_pixbuf_scale_simple(pixbuf, 500, 300, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(img), pxbscaled);
g_assert_no_error(err);
}
Here is my full code:
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdarg.h>
#include <gphoto2/gphoto2-camera.h>
#include <gphoto2/gphoto2-context.h>
#include <wiringPi.h>
#include <gtk/gtk.h>
#include <pthread.h>
//program
static int running = 1;
//libgphoto2
static CameraList* list;
static Camera** cams;
static GPContext* context;
static const char *name, *value;
static int ret, count;
static int pic = 0;
static int front = 1;
//GTK
static GtkWidget *window, *hbox, *hbox2, *vbox, *button1;
static GtkWidget *front_cams[3];
static GtkWidget *back_cams[3];
static GdkPixbuf *pxbscaled;
static GdkPixbuf *pixbuf;
static GError* err = NULL;
static void button_clicked(GtkWidget *widget, gpointer data) {
gtk_button_set_label(GTK_BUTTON(button1), "click me 2"); //change button text
}
void *main_gtk() {
//INIT GTK
gtk_init(NULL, NULL);
//SETUP WINDOW
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
//button1=gtk_button_new_with_label("Click me");
//gtk_button_set_label(GTK_BUTTON(button1), "click me 1");
g_signal_connect(window,"delete-event", G_CALLBACK(gtk_main_quit), NULL);
//g_signal_connect(button1, "clicked", G_CALLBACK(button_clicked), NULL);
//SET WINDOW SIZE AND TITLE
//gtk_widget_set_size_request(window, 600, 400);
gtk_window_set_title(GTK_WINDOW(window), "CaptureGui");
//RESIZE IMAGES
//image
front_cams[0] = gtk_image_new();
front_cams[1] = gtk_image_new();
front_cams[2] = gtk_image_new();
back_cams[0] = gtk_image_new();
back_cams[1] = gtk_image_new();
back_cams[2] = gtk_image_new();
//g_print("1");
//set_image_scaled(front_cams[0], "/media/pi/SD CARD/cam-1_1_a_front.jpg");
//set_image_scaled(front_cams[1], "/media/pi/SD CARD/cam-1_1_a_front.jpg");
//set_image_scaled(front_cams[2], "/media/pi/SD CARD/cam-1_1_b_back.jpg");
//PACK
hbox = gtk_hbox_new(0, 0);
gtk_box_pack_start(GTK_BOX(hbox), front_cams[0], 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hbox), front_cams[1], 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hbox), front_cams[2], 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hbox), back_cams[0], 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hbox), back_cams[1], 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hbox), back_cams[2], 0, 0, 0);
gtk_container_add(GTK_CONTAINER(window), hbox);
//ADD ELEMENTS TO GUI
//gtk_container_add(GTK_CONTAINER(window), image1);
//gtk_container_add(GTK_CONTAINER(window), image2);
//image2 = gtk_image_new_from_file("/media/pi/SD CARD/cam-1_0_b_back.jpg");
//gtk_container_add(GTK_CONTAINER(window), image2);
//SHOW GUI
gtk_widget_show_all(window);
gtk_main();
}
void set_image_scaled(GtkWidget *img, const char *path) {
pixbuf = gdk_pixbuf_new_from_file(path, &err);
pxbscaled = gdk_pixbuf_scale_simple(pixbuf, 500, 300, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(img), pxbscaled);
g_assert_no_error(err);
}
void *cam_main() {
while (running == 1) {
if (digitalRead(4) == 0) {
printf("taking pics of %s item %i\n", (front == 1) ? "front" : "back", pic);
for (int i = 0; i < count; i++) {
int fd, retval;
CameraFile *file;
CameraFilePath cfPath;
strcpy(cfPath.folder, "/");
strcpy(cfPath.name, "foo1.jpg");
printf("Capturing cam%i...\n", i + 1);
int res = gp_camera_capture(cams[i], GP_CAPTURE_IMAGE, &cfPath, context);
//printf(gp_port_result_as_string(res));
printf("capture result: %i\n", res);
//Camera won't take pic if busy and will continue to program end
char buf[256];
snprintf(buf, sizeof(buf), "/media/pi/SD CARD/cam-%i_%i_%s.jpg", i + 1, pic, (front == 1) ? "a_front" : "b_back"); //a_ to make front come before back otherwise systems will order incorrectly
fd = open(buf, O_CREAT | O_WRONLY, 0644);
retval = gp_file_new_from_fd(&file, fd);
retval = gp_camera_file_get(cams[i], cfPath.folder, cfPath.name, GP_FILE_TYPE_NORMAL, file, context);
retval = gp_camera_file_delete(cams[i], cfPath.folder, cfPath.name, context);
gp_file_free(file);
if (front == 1)
set_image_scaled(front_cams[i], buf);
else
set_image_scaled(back_cams[i], buf);
}
if (front == 1)
front = 0;
else {
front = 1;
pic += 1;
}
printf("pics taken...\n");
}
}
}
int main(int argc, char **argv) {
//Kill any processes using cams
system("pkill -f gphoto2");
//main_gtk();
//Wiring pi init
wiringPiSetupGpio();
//Init
context = gp_context_new();
detect_cams();
pthread_t logic_thread_handle, gui_thread_handle;
pthread_create(&logic_thread_handle, NULL, cam_main, NULL);
pthread_create(&gui_thread_handle, NULL, main_gtk, NULL);
pthread_join(gui_thread_handle, 0);
pthread_join(logic_thread_handle, 0);
//Deinit
for (int i = 0; i < count; i++) {
gp_camera_exit(cams[i], context);
gp_camera_free(cams[i]);
}
return 0;
}
void detect_cams() {
//Detecting all cameras and loading them into mem
//Detecting all cameras
ret = gp_list_new(&list);
if (ret < GP_OK) return 1;
gp_list_reset(list);
count = gp_camera_autodetect(list, context);
if (count < 1) {
printf("No cameras detected.\n");
return 1;
}
//Open all cameras
printf("Number of cameras: %d\n", count);
cams = calloc(sizeof (Camera*), count);
for (int i = 0; i < count; i++) {
gp_list_get_name(list, i, &name);
gp_list_get_value(list, i, &value);
ret = open_cam(&cams[i], name, value, context);
if (ret < GP_OK)
fprintf(stderr, "Camera %s on port %s failed to open\n", name, value);
}
}
int open_cam(Camera ** camera, const char *model, const char *port, GPContext *context) {
GPPortInfoList *portinfolist = NULL;
CameraAbilitiesList *abilities = NULL;
int ret, m, p;
CameraAbilities a;
GPPortInfo pi;
ret = gp_camera_new (camera);
if (ret < GP_OK) return ret;
if (!abilities) {
/* Load all the camera drivers we have... */
ret = gp_abilities_list_new (&abilities);
if (ret < GP_OK) return ret;
ret = gp_abilities_list_load (abilities, context);
if (ret < GP_OK) return ret;
}
/* First lookup the model / driver */
m = gp_abilities_list_lookup_model (abilities, model);
if (m < GP_OK) return ret;
ret = gp_abilities_list_get_abilities (abilities, m, &a);
if (ret < GP_OK) return ret;
ret = gp_camera_set_abilities (*camera, a);
if (ret < GP_OK) return ret;
if (!portinfolist) {
/* Load all the port drivers we have... */
ret = gp_port_info_list_new (&portinfolist);
if (ret < GP_OK) return ret;
ret = gp_port_info_list_load (portinfolist);
if (ret < 0) return ret;
ret = gp_port_info_list_count (portinfolist);
if (ret < 0) return ret;
}
/* Then associate the camera with the specified port */
p = gp_port_info_list_lookup_path (portinfolist, port);
switch (p) {
case GP_ERROR_UNKNOWN_PORT:
fprintf(stderr, "The port you specified "
"('%s') can not be found. Please "
"specify one of the ports found by "
"'gphoto2 --list-ports' and make "
"sure the spelling is correct "
"(i.e. with prefix 'serial:' or 'usb:').",
port);
break;
default:
break;
}
if (p < GP_OK) return p;
ret = gp_port_info_list_get_info (portinfolist, p, &pi);
if (ret < GP_OK) return ret;
ret = gp_camera_set_port_info (*camera, pi);
if (ret < GP_OK) return ret;
return GP_OK;
}
Probably a lot of memory is occupied by unreleased GdkPixbufs.
Try this:
void set_image_scaled(GtkWidget *img, const char *path) {
pixbuf = gdk_pixbuf_new_from_file(path, &err);
g_assert_no_error(err);
pxbscaled = gdk_pixbuf_scale_simple(pixbuf, 500, 300, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(img), pxbscaled);
g_object_unref(pixbuf);
g_object_unref(pxbscaled);
}
Reference Counting and Memory Mangement

libX11: XPutImage first call

I've created XImage using XCreateImage and use XPutImage to display it on window, but XPutImage shows this picture only on second call of it. Why this happens?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
void draw(char *rgb_out, int w, int h)
{
int i = 0;
for (i = 0;i < w*h;i += 4) {
rgb_out[i + 1] = 0;
rgb_out[i + 2] = 0;
rgb_out[i + 3] = 0;
}
return;
}
XImage *create_ximage(Display *display, Visual *visual, int width, int height)
{
char *image32 = (char *)malloc(width * height * 4);
draw(image32, width, height);
return XCreateImage(display, visual, 24,
ZPixmap, 0, image32,
width, height, 32, 0);
}
int main(int argc, char **argv)
{
int win_b_color;
int win_w_color;
XEvent xev;
Window window;
GC gc;
Display *display = XOpenDisplay(NULL);
Visual *visual;
XImage *ximage;
win_b_color = BlackPixel(display, DefaultScreen(display));
win_w_color = BlackPixel(display, DefaultScreen(display));
window = XCreateSimpleWindow(display,
DefaultRootWindow(display),
0, 0, 600, 400, 0,
win_b_color, win_w_color);
gc = XCreateGC(display, window, 0, NULL);
visual = DefaultVisual(display, 0);
XMapWindow(display, window);
XFlush(display);
ximage = create_ximage(display, visual, 100, 100);
while (1) {
int r;
r = XPutImage(display, window,
gc, ximage, 0, 0, 0, 0,
100, 100);
printf("RES: %i\n", r);
XSync(display, 1);
XFlush(display);
getchar();
}
return 0;
}
The trick is to wait that the windows is mapped. You can do this by Expose event.
int main(int argc, char **argv)
{
int win_b_color;
int win_w_color;
XEvent xev;
Window window;
GC gc;
Display *display = XOpenDisplay(NULL);
Visual *visual;
XImage *ximage;
win_b_color = BlackPixel(display, DefaultScreen(display));
win_w_color = BlackPixel(display, DefaultScreen(display));
window = XCreateSimpleWindow(display,
DefaultRootWindow(display),
0, 0, 600, 400, 0,
win_b_color, win_w_color);
visual = DefaultVisual(display, 0);
XSelectInput(display, window, ExposureMask | KeyPressMask);
XMapWindow(display, window);
XFlush(display);
gc = XCreateGC(display, window, 0, NULL);
ximage = create_ximage(display, visual, 100, 100);
XEvent event;
bool exit = false;
while (!exit) {
int r;
XNextEvent(display, &event);
if (event.type == Expose)
{
r = XPutImage(display, window,
gc, ximage, 0, 0, 0, 0,
100, 100);
printf("RES: %i\n", r);
}
else if (event.type == KeyPress)
exit = true;
}
return 0;
}

How to access memory mapped file created by parent process in C (Windows)

I created the mapped file and read from view in the parent process. However, I couldn't make the child process access the memory-mapped file. Can you please examine the code below and help me figure it out?
Here is my child process code:
#include <Windows.h>
#include <stdio.h>
#define SIZE 1024 *40
int main(){
HANDLE hLogMap;
char* pView, *start;
if((hLogMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "a.txt")) == NULL)
{
fprintf(stderr,"Unable to open memory mapping: %d\n", GetLastError());
}
if((pView = (char *) MapViewOfFile(hLogMap, FILE_MAP_ALL_ACCESS, 0, 0, SIZE)) == NULL)
{
fprintf(stderr,"Unable to create map view: %d\n", GetLastError());
}
start=pView;
while(pView < start + SIZE){
fprintf(stderr,*(pView++));
pView++;
}
system("pause");
return 1;
}
Here is the parent code:
#include <Windows.h>
#include <stdio.h>
#define BUFF_SIZE 1024 *40
#define FILE_NAME "a.txt"
void exitPrompt(){
system("pause");
exit(0);
}
void main(){
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sa;
char* lpCommandLine="child.exe";
HANDLE hFile, hMMap, handle;
char * pFile, * start, *rFile;
SecureZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
SecureZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
if (!CreateProcess(NULL, lpCommandLine, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
printf("unable to create new process!");
system("pause");
exit(0);
}
else
{
printf("parent is now working!\n");
handle = pi.hProcess;
}
if((hFile = CreateFile( FILE_NAME,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_WRITE|FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL))
== INVALID_HANDLE_VALUE){
fprintf(stderr,"Unable to open file %s: %d\n",FILE_NAME,GetLastError());
exitPrompt();
}
if((hMMap = CreateFileMapping( hFile,
&sa,
PAGE_READWRITE,
0,
BUFF_SIZE,
NULL))
== NULL){
fprintf(stderr,"Unable to create memory mapping: %d\n",GetLastError());
exitPrompt();
}
if( ( pFile = (char *) MapViewOfFile( hMMap,
FILE_MAP_WRITE,
0,
0,
BUFF_SIZE))
== NULL)
{
fprintf(stderr,"Unable to create map view: %d\n",GetLastError());
exitPrompt();
}
start = pFile;
while(pFile < start + BUFF_SIZE){
*(pFile++) = 'f';
*(pFile++) = 'i';
*(pFile++) = 'g';
*(pFile++) = 'e';
*(pFile++) = 'n';
*(pFile++) = 'g';
*(pFile++) = '_';
*(pFile++) = 10; //in ascii 10 is new line
}
if( ( rFile = (char *) MapViewOfFile( hMMap,
FILE_MAP_READ,
0,
0,
BUFF_SIZE))
== NULL)
{
fprintf(stderr,"Unable to create map view: %d\n",GetLastError());
exitPrompt();
}
rFile=start;
/*while(rFile < start + BUFF_SIZE){
printf("%c",*(rFile));
rFile++;
}*/
WaitForSingleObject(handle,INFINITE);
CloseHandle(handle);
CloseHandle(pi.hThread);
CloseHandle(hMMap);
CloseHandle(hFile);
exitPrompt();
}
The OpenFileMapping expected the mapping name not the file in itself.
if((hLogMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "mapping")) == NULL)
...
When you create the mapping provide the mapping name in the CreateFileMapping.
if((hMMap = CreateFileMapping( hFile,
&sa,
PAGE_READWRITE,
0,
BUFF_SIZE,
"mapping"))
== NULL){
fprintf(stderr,"Unable to create memory mapping: %d\n",GetLastError());
Possibly share the mapping name between your child and parent and use a random name.

Resources