/*[]=====================================================================[]*/ /*[] LEADTOOLS for Windows - Version 11 []*/ /*[] []*/ /*[] []*/ /*[] Copyright (c) 1991-2000 LEAD Technologies, Inc. []*/ /*[] All Rights Reserved. []*/ /*[]=====================================================================[]*/ /*---(thread)--------------------------------------------------------------- LEAD Functions Used. L_SetDisplayMode L_LoadBitmap L_PaintDCEffect L_InitBitmap L_FreeBitmap We have made the assumption that the user has the knowledge of programing in C and Windows. In describing this example I will refer to the main program as the 'main thread', while the thread created with_beginthread will be referred to as the 'secondary thread'. This example will: 1. Create a socundary thread that will load all files from the directory specified as parameter on the command line. If no parameter is passed, the local directory is used. 2. The main thread (main program) will paint the images loaded by the secondary thread. If a load takes too long, it will repaint the current image using a paint effect, cycling through all the effects. 3. The program uses a global static variable for the current bitmap. They both have to access the same bitmap and they use a mutex for synchronization (hBitmapMutex). 4. It is possible for the secondary thread to be able to load two images while the main thread paints the current images, especially when using an effect that takes longer to paint (like random pixels). To avoid that, a semaphore (hImagePaintedSemaphore) is used. The semaphore is signaled by the secondary thread after it loads an image and waits for it to be nonsignaled by the main thread when it had painted it. 5. To give a clue about what is going on, the window title shows what is the secondary thread doing. If the secondary thread would set the window title directly calling SetWindowText, that would involve calling SendMessage(WM_SETTEXT) which would wait for the main thread to finish processing the current message (possibly a paint effect) and then process the WM_SETTEXT message. To avoid that, the secondary thread call PostMessage to signal the main thread that it should change its title. Because a static buffer is used to store the window title, a mutex is used (hWindowTitleMutex) for synchronization. 6. When the secondary thread has finished loading all the images, it quits and the program waits for the user to close the program. 7. If the user tries to close down the program while the secondary thread is loading images, it signals the secondary thread to abort itself and waits for that thread to kill itself. It doesn't try to kill the secondary thread because that could lead to memory leaks. 8. There are two loops going on at the same thread: the message loop in the main thread and the do..while loop in the secondary loop. Usage: thread --------------------------------------------------------------------------*/ #include /* Required for all Windows applications. */ #include /* Windows header for message cracker. */ #include /* Standard C library for _fmemcpy. */ #include #include #include #include #include "TCHAR.h" #include "..\\..\\..\\include\\l_bitmap.h" /* LEADTOOLS main header file. */ #include "..\\..\\..\\include\\l_error.h" /* LEADTOOLS error definition header file. */ #include "thread.h" /* Application specific header file. */ static int nEffectIndex[] = { EFX_EFFECT_WIPE_CLASS, EFX_EFFECT_WIPE_MAX, EFX_EFFECT_WIPE_RECTANGLE_CLASS, EFX_EFFECT_WIPE_RECTANGLE_MAX, EFX_EFFECT_WIPE_CIRCLE_CLASS, EFX_EFFECT_WIPE_CIRCLE_MAX, EFX_EFFECT_PUSH_CLASS, EFX_EFFECT_PUSH_MAX, EFX_EFFECT_SLIDE_CLASS, EFX_EFFECT_SLIDE_MAX, EFX_EFFECT_ROLL_CLASS, EFX_EFFECT_ROLL_MAX, EFX_EFFECT_ROTATE_CLASS, EFX_EFFECT_ROTATE_MAX, EFX_EFFECT_ZOOM_CLASS, EFX_EFFECT_ZOOM_MAX, EFX_EFFECT_DRIP_CLASS, EFX_EFFECT_DRIP_MAX, EFX_EFFECT_BLIND_CLASS, EFX_EFFECT_BLIND_MAX, EFX_EFFECT_RANDOM_CLASS, EFX_EFFECT_RANDOM_MAX, EFX_EFFECT_CHECKERBOARD_CLASS, EFX_EFFECT_CHECKERBOARD_MAX, EFX_EFFECT_BLOCKS_CLASS, EFX_EFFECT_BLOCKS_MAX, EFX_EFFECT_CIRCLE_CLASS, EFX_EFFECT_CIRCLE_MAX, EFX_EFFECT_ELLIPSE_CLASS, EFX_EFFECT_ELLIPSE_MAX, }; L_BOOL ExtractCommandData ( ) ; /*---[WinMain]--------------------------------------------------------------- Syntax: int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) Parameters: hInstance Current instance. hPrevInstance previous instance. lpCmdLine command line. nCmdShow show-window type. Prototype: Windows.h Notes: Windows main function, calls initialization function and processes message loop. --------------------------------------------------------------------------*/ int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; /* Windows' Message variable for holding messages */ UNLOCKSUPPORT(); if (!hPrevInstance) /* Other instances of app running? */ if (!InitApplication (hInstance)) /* Initialize shared things. */ return (FALSE); /* Exits if unable to initialize. */ ExtractCommandData ( ) ; if (!InitInstance (hInstance, nCmdShow)) /* Do instance initializations. */ return (FALSE); /* Acquire and dispatch messages until a WM_QUIT message is received. */ do { if(PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { if( msg.message == WM_QUIT ) break; TranslateMessage (&msg); /* Translates virtual key codes. */ DispatchMessage (&msg); /* Dispatches message to window. */ } else if(bKillThread) WaitMessage(); else { if( WaitForSingleObject(hWindowTitleMutex,1000) == WAIT_OBJECT_0 ) { SetWindowText(hMainWnd, szWindowTitle); ReleaseMutex(hWindowTitleMutex); } Sleep(500); if( !PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) PostMessage(hMainWnd, WM_COMMAND, IDM_REPAINTWINDOW, TRUE); } } while(TRUE); return (msg.wParam); /* Returns the value from PostQuitMessage. */ } /*---[InitApplication]------------------------------------------------------ Syntax: L_BOOL InitApplication( HANDLE hInstance ) Parameters: hInstance Current instance. Prototype: thread.h Notes: Initializes window class structure and registers window class. --------------------------------------------------------------------------*/ L_BOOL InitApplication (HANDLE hInstance) { WNDCLASS wcWindowClass; wcWindowClass.style = 0; /* Class style(s). */ wcWindowClass.lpfnWndProc = MainWndProc; /* Function to retrieve messages */ /* for windows of this class. */ wcWindowClass.cbClsExtra = 0;/* No per-class extra data. */ wcWindowClass.cbWndExtra = 0;/* No per-window extra data. */ wcWindowClass.hInstance = hInstance; /* Owner. */ wcWindowClass.hIcon = LoadIcon (hInstance, TEXT("LEAD")); wcWindowClass.hCursor = LoadCursor (NULL, IDC_ARROW); wcWindowClass.hbrBackground = GetStockObject (WHITE_BRUSH); wcWindowClass.lpszMenuName = NULL; /* No menu. */ wcWindowClass.lpszClassName = TEXT("LEADWClass"); /* Name. */ /* Register the window class and return the result code. */ return (RegisterClass (&wcWindowClass)); } /*---[InitInstance]---------------------------------------------------------- Syntax: L_BOOL InitInstance( HANDLE hInstance, L_INT nCmdShow ) Parameters: hInstance Current instance. nCmdShow Param for first ShowWindow() call. Prototype: thread.h Notes: Saves instance and Creates main window. --------------------------------------------------------------------------*/ L_BOOL InitInstance (HANDLE hInstance, L_INT nCmdShow) { nMaximizedWidth = GetSystemMetrics(SM_CXMAXIMIZED) - 2 * GetSystemMetrics(SM_CXFRAME); nMaximizedHeight = GetSystemMetrics(SM_CYMAXIMIZED) - 2 * GetSystemMetrics(SM_CYFRAME); hInst = hInstance; /* Set Ordered Dithering for the Display */ L_SetDisplayMode (DISPLAYMODE_ORDEREDDITHER | DISPLAYMODE_FAVORBLACK, DISPLAYMODE_ORDEREDDITHER | DISPLAYMODE_FAVORBLACK); /* Set up RECT for window sizing. */ rWndSize.top = 0; rWndSize.left = 0; rWndSize.bottom = 400; rWndSize.right = 400; AdjustWindowRect (&rWndSize, WS_OVERLAPPEDWINDOW, FALSE); hMainWnd = CreateWindow ( TEXT("LEADWClass"), TEXT("LEADTOOLS Sample Thread Application"), /* Window title */ WS_OVERLAPPEDWINDOW, /* Window style. */ CW_USEDEFAULT, /* Default horizontal position. */ CW_USEDEFAULT, /* Default vertical position. */ rWndSize.right - rWndSize.left, /* Window width. */ rWndSize.bottom - rWndSize.top, /* Window height. */ NULL, /* Overlapped windows have no parent. */ NULL, /* Use the window class menu. */ hInstance, /* This instance owns this window. */ NULL /* Pointer not needed. */ ); if (hMainWnd == NULL) return (FALSE); /* If window could not be created, return "failure" */ ShowWindow (hMainWnd, SW_SHOWMAXIMIZED); /* Show the window. */ UpdateWindow (hMainWnd); /* Sends WM_PAINT message. */ /* create a mutex for Data.Bitmap */ hBitmapMutex = CreateMutex( NULL, TRUE, TEXT("LEADThreadSample_Data_Bitmap") ); if( !hBitmapMutex ) { MessageBox(NULL, TEXT("Cannot create mutex object"), TEXT("ERROR"), MB_OK|MB_ICONERROR); DestroyWindow( hMainWnd ); return FALSE; } /* create a mutex for the szWindowTitle string */ hWindowTitleMutex = CreateMutex( NULL, TRUE, TEXT("LEADThreadSample_Window_Title") ); if( !hWindowTitleMutex ) { MessageBox(NULL, TEXT("Cannot create mutex object"), TEXT("ERROR"), MB_OK|MB_ICONERROR); CloseHandle(hBitmapMutex); DestroyWindow( hMainWnd ); return FALSE; } hImagePaintedSemaphore = CreateSemaphore( NULL, 1, 1, TEXT("LEADThreadSample_Data_Bitmap2") ); if( !hImagePaintedSemaphore ) { MessageBox(NULL, TEXT("Cannot create semaphore object"), TEXT("ERROR"), MB_OK|MB_ICONERROR); CloseHandle(hWindowTitleMutex); CloseHandle(hBitmapMutex); DestroyWindow( hMainWnd ); return FALSE; } L_InitBitmap(&Data.BitmapHandle, sizeof(BITMAPHANDLE), 1, 1, 1); /* make the mutex available to the thread that is soon to be created */ ReleaseMutex( hBitmapMutex ); ReleaseMutex( hWindowTitleMutex ); if( (lThread = _beginthread( ThreadMainProc, 30000, NULL )) == -1 ) { MessageBox(NULL, TEXT("Cannot create thread"), TEXT("ERROR"), MB_OK|MB_ICONERROR); DestroyWindow( hMainWnd ); return FALSE; } return (TRUE); } /*---[MainWndProc]----------------------------------------------------------- Syntax: L_INT32 EXT_FUNCTION MainWndProc( HWND hWnd, L_UINT message, WPARAM wParam, LPARAM lParam ) Parameters: hWnd Window handle. message Type of message. wParam Additional information. lParam Additional information. Prototype: thread.h Notes: This procedure is responsible for dispatching window messages. --------------------------------------------------------------------------*/ L_INT32 EXT_FUNCTION MainWndProc (HWND hWnd, L_UINT Message, WPARAM wParam, LPARAM lParam) { switch (Message) { HANDLE_MSG (hWnd, WM_COMMAND, Window_OnCommand); HANDLE_MSG (hWnd, WM_QUERYNEWPALETTE, Window_OnQueryNewPalette); HANDLE_MSG (hWnd, WM_PALETTECHANGED, Window_OnPaletteChanged); HANDLE_MSG (hWnd, WM_PALETTEISCHANGING, Window_OnPaletteChanging); HANDLE_MSG (hWnd, WM_SYSCOLORCHANGE, Window_SysColorChange); HANDLE_MSG (hWnd, WM_ACTIVATE, Window_OnActivate); HANDLE_MSG (hWnd, WM_PAINT, Window_OnPaint); HANDLE_MSG (hWnd, WM_SIZE, Window_OnSize); HANDLE_MSG (hWnd, WM_CLOSE, Window_OnClose); HANDLE_MSG (hWnd, WM_DESTROY, Window_OnDestroy); } return DefWindowProc (hWnd, Message, wParam, lParam); } /*---[Window_OnCommand]----------------------------------------------------- Syntax: VOID Window_OnCommand( HWND hWnd, L_INT id, HWND hwndCtl, UINT codeNotify ) Parameters: hWnd Window handle. id Menu item or Control ID. hwndCtl 0 if menu item selected, else window handle of the control. codeNotify 1 if accelerator keystroke, else notification code, such as BN_CLICKED. Prototype: thread.h Notes: This procedure is responsible for handling WM_COMMAND. --------------------------------------------------------------------------*/ L_INT Window_OnCommand (HWND hWnd, L_INT id, HWND hwndCtl, UINT codeNotify) { switch(id) { case IDM_SETWINDOWTITLE: /* don't wait too long - setting the window title is not that important */ if( WaitForSingleObject(hWindowTitleMutex, 1000) == WAIT_OBJECT_0 ) { SetWindowText(hMainWnd, szWindowTitle); ReleaseMutex(hWindowTitleMutex); } break; case IDM_REPAINTWINDOW: RepaintWindow((L_BOOL)hwndCtl); break; case IDM_DESTROYWINDOW: DestroyWindow(hWnd); break; } return 0; } /*---[Window_OnActivate]----------------------------------------------------- Syntax: VOID Window_OnActivate(HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized) Parameters: hWnd Window handle. state WA_ACTIVE | WA_CLICKACTIVE | WA_INACTIVE hwndActDeact the winodw habdle that deactivate fMinimized Window is minimized Prototype: Color.h Notes: This procedure is responsible for handling WM_ONCOMMAND. --------------------------------------------------------------------------*/ void Window_OnActivate(HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized) { if(state!=WA_INACTIVE) Window_OnQueryNewPalette (hwnd); } /*----(Window_OnPaletteChanged)-------------------------------------------- Syntax: VOID Window_OnPaletteChanged( HWND hWnd, HWND hWndPaletteChange ) Parameters: hwnd Handle to a window. hWndPaletteChange Handle to a window that has the palette realized. Prototype: thread.h Notes: This procedure is responsible for handling WM_PALETTECHANGED. --------------------------------------------------------------------------*/ VOID Window_OnPaletteChanged (HWND hWnd, HWND hWndPaletteChange) { HDC hDC; HPALETTE hPalette; /* If this window initiated the palette change, do nothing. */ if (hWnd == hWndPaletteChange) return; WaitForSingleObject( hBitmapMutex, INFINITE ); /* Delete the previous palette, if there is one. */ if (Data.hPalette) { DeleteObject (Data.hPalette); Data.hPalette = NULL; } /* Does this window have a bitmap and a palette? */ if (Data.BitmapHandle.Flags.Allocated) { hDC = GetDC (hWnd); /* Generate a new logical palette (if needed) for painting. */ Data.hPalette = L_CreatePaintPalette (hDC, &Data.BitmapHandle); /* Select and Realize the palette. */ hPalette = SelectPalette (hDC, Data.hPalette, TRUE); RealizePalette (hDC); /* Force a repaint. */ InvalidateRect (hWnd, NULL, FALSE); /* Return the old palette. */ SelectPalette (hDC, hPalette, TRUE); ReleaseDC (hWnd, hDC); } ReleaseMutex( hBitmapMutex ); return; } /*----(Window_OnQueryNewPalette)-------------------------------------------- Syntax: BOOL Window_OnQueryNewPalette( HWND hWnd ) Parameters: hWnd Handle to a window. Prototype: thread.h Notes: This procedure is responsible for handling WM_QUERYNEWPALETTE. --------------------------------------------------------------------------*/ BOOL Window_OnQueryNewPalette (HWND hWnd) { HDC hDC; HPALETTE hPalette; L_INT nNoColors = 0; WaitForSingleObject( hBitmapMutex, INFINITE ); /* Delete the previous palette, if there is one. */ if (Data.hPalette) { DeleteObject (Data.hPalette); Data.hPalette = NULL; } if (Data.BitmapHandle.Flags.Allocated) { hDC = GetDC (hWnd); /* Generate a new logical palette (if needed) for painting. */ Data.hPalette = L_CreatePaintPalette (hDC, &Data.BitmapHandle); /* Is a palette needed? */ if (Data.hPalette) { hPalette = SelectPalette (hDC, Data.hPalette, FALSE); nNoColors = RealizePalette (hDC); if (nNoColors) /* If the palette changed, force a WM_PAINT. */ InvalidateRect (hWnd, NULL, FALSE); /* Restore the old palette. */ SelectPalette (hDC, hPalette, TRUE); } ReleaseDC (hWnd, hDC); } ReleaseMutex(hBitmapMutex); return (nNoColors); } /*====(Window_OnPaletteChanging)========================================== Description: Enumerates all child windows and asks them to realize their logical palettes beside the physical palette. Syntax : VOID Window_OnPaletteChanging(HWND hwnd, HWND hWndPaletteChange) Parameters : hwnd Handle to a window. hWndPaletteChange Handle to a window that has the palette realized. Return Value: None. ==========================================================================*/ VOID Window_OnPaletteChanging(HWND hWnd, HWND hWndPaletteChange) { Window_OnPaletteChanged (hWnd, hWndPaletteChange); } /*====(Window_SysColorChange)========================================== Syntax: VOID Window_SysColorChange( HWND hWnd ) Parameters: hWnd Handle to a window. Prototype: Loadsave.h Notes: This procedure is responsible for handling WM_SYSCOLORCHANGE. --------------------------------------------------------------------------*/ VOID Window_SysColorChange(HWND hwnd) { Window_OnQueryNewPalette (hwnd); } /*---[Window_OnPaint]------------------------------------------------------- Syntax: VOID Window_OnPaint( HWND hWnd ); Parameters: hWnd Window handle. Prototype: thread.h Notes: This procedure is responsible for handling WM_PAINT. --------------------------------------------------------------------------*/ VOID Window_OnPaint (HWND hWnd) { HDC hdc; RECT rc; RECT rcClient; PAINTSTRUCT ps; HPALETTE hOldPal = NULL; WaitForSingleObject( hBitmapMutex, INFINITE ); hdc = BeginPaint (hWnd, &ps);/* Get DC */ if (!bDisableRepaint && Data.BitmapHandle.Flags.Allocated) /* Do we have an image? */ { if (Data.hPalette) /* Is there a palette that needs to be selected? */ hOldPal = SelectPalette (hdc, Data.hPalette, TRUE); /* Select it */ #ifndef WHITE_BACKGROUND FillRect(hdc, &ps.rcPaint, GetStockObject(GRAY_BRUSH)); #endif /* Setup the Destination Rectangle. */ SetRect (&rc, 0, 0, BITMAPWIDTH(&Data.BitmapHandle), BITMAPHEIGHT(&Data.BitmapHandle)); GetClientRect(hWnd, &rcClient); if( rcClient.right >= BITMAPWIDTH(&Data.BitmapHandle) && rcClient.bottom >= BITMAPHEIGHT(&Data.BitmapHandle)) { /* display the image in the center */ SetRect( &rc, 0, 0, BITMAPWIDTH(&Data.BitmapHandle), BITMAPHEIGHT(&Data.BitmapHandle)); OffsetRect( &rc, (rcClient.right - BITMAPWIDTH(&Data.BitmapHandle))/2, (rcClient.bottom - BITMAPHEIGHT(&Data.BitmapHandle))/2 ); } else { /* fit width: ratio = image_width/window_width */ if( BITMAPWIDTH(&Data.BitmapHandle) * rcClient.bottom >= BITMAPHEIGHT(&Data.BitmapHandle) * rcClient.right ) SetRect( &rc, 0, 0, rcClient.right, MulDiv(rcClient.right,BITMAPHEIGHT(&Data.BitmapHandle),BITMAPWIDTH(&Data.BitmapHandle))); else SetRect( &rc, 0, 0, MulDiv(rcClient.bottom,BITMAPWIDTH(&Data.BitmapHandle),BITMAPHEIGHT(&Data.BitmapHandle)), rcClient.bottom); OffsetRect( &rc, (rcClient.right - (rc.right - rc.left)) / 2, (rcClient.bottom - (rc.bottom - rc.top)) / 2 ); } if (nPaintEffect > nEffectIndex[nClassEffect+1]) { nClassEffect += 2; if (nClassEffect >= sizeof(nEffectIndex) / sizeof(nEffectIndex[0])) { nClassEffect = 0; } nPaintEffect = nEffectIndex[nClassEffect]; } /* Paint it */ L_PaintDCEffect (hdc, &Data.BitmapHandle, NULL, NULL, &rc, &ps.rcPaint, SRCCOPY, nPaintEffect++); if (Data.hPalette) /* Return old palette, if there is one. */ SelectPalette (hdc, hOldPal, TRUE); } EndPaint (hWnd, &ps); /* Return DC */ ReleaseMutex( hBitmapMutex ); } /*---[Window_OnPaint]------------------------------------------------------- Syntax: VOID Window_OnSize (HWND hWnd, UINT sizeType, L_INT cx, L_INT cy) Parameters: hWnd Window handle. Prototype: thread.h Notes: This procedure is responsible for handling WM_SIZE. --------------------------------------------------------------------------*/ VOID Window_OnSize (HWND hWnd, UINT sizeType, L_INT cx, L_INT cy) { InvalidateRect( hWnd, NULL, FALSE ); } /*---[Window_OnClose]---------------------------------------------------- Syntax: VOID Window_OnClose( HWND hWnd ); Parameters: hWnd Window handle. Prototype: thread.h Notes: This procedure is responsible for handling WM_CLOSE. --------------------------------------------------------------------------*/ VOID Window_OnClose (HWND hWnd) { /* if the thread is active, signal it to kill itself */ if( lThread ) { SetWindowText( hWnd, TEXT("Killing the thread") ); bKillThread = TRUE; } else DestroyWindow( hWnd ); } /*---[Window_OnDestroy]---------------------------------------------------- Syntax: VOID Window_OnDestroy( HWND hWnd ); Parameters: hWnd Window handle. Prototype: thread.h Notes: This procedure is responsible for handling WM_DESTROY. --------------------------------------------------------------------------*/ VOID Window_OnDestroy (HWND hWnd) { UNREFERENCED_PARAMETER (hWnd); if (Data.BitmapHandle.Flags.Allocated) /* Do we have an image? */ L_FreeBitmap (&Data.BitmapHandle); if (Data.hPalette) /* Delete palette if there is one. */ DeleteObject (Data.hPalette); if(hWindowTitleMutex) CloseHandle(hWindowTitleMutex); if(hBitmapMutex) CloseHandle(hBitmapMutex); if(hImagePaintedSemaphore) CloseHandle(hImagePaintedSemaphore); PostQuitMessage (0); /* Post WM_QUIT, to end the application. */ return; } /* when we got a new images, repaint the window */ L_VOID RepaintWindow(L_BOOL bSameImage) { HDC hDC; /* no more repainting if I want to quit */ if( bKillThread ) return; /* create the palette with a code similar with the one from WM_QUERYNEWPALETTE */ bDisableRepaint = TRUE; WaitForSingleObject( hBitmapMutex, INFINITE ); if( bImageUpdated ) bImageUpdated = FALSE; if( !bSameImage ) { hDC = GetDC (hMainWnd); /* Generate a new logical palette (if needed) for painting. */ Data.hPalette = L_CreatePaintPalette (hDC, &Data.BitmapHandle); /* Is a palette needed? */ if (Data.hPalette) { HPALETTE hPalette = SelectPalette (hDC, Data.hPalette, TRUE); /* Even if the palette changes, don't repaint yet. */ RealizePalette (hDC); /* Restore the old palette. */ SelectPalette (hDC, hPalette, TRUE); } ReleaseDC (hMainWnd, hDC); } InvalidateRect( hMainWnd, NULL, FALSE ); #ifdef ADJUST_WINDOW_SIZE if( !bSameImage ) { RECT rc; GetClientRect( hMainWnd, &rc ); if( rc.right < BITMAPWIDTH(&Data.BitmapHandle) || rc.bottom < BITMAPHEIGHT(&Data.BitmapHandle)) { SetRect(&rc, 0, 0, BITMAPWIDTH(&Data.BitmapHandle), BITMAPHEIGHT(&Data.BitmapHandle)); AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); MoveWindow( hMainWnd, 0, 0, min(nMaximizedWidth,rc.right-rc.left), min(nMaximizedHeight,rc.bottom-rc.top), TRUE ); } } #endif bDisableRepaint = FALSE; InvalidateRect(hMainWnd, NULL, TRUE); UpdateWindow(hMainWnd); ReleaseMutex(hBitmapMutex); if( !bSameImage ) ReleaseSemaphore(hImagePaintedSemaphore,1,NULL); } L_VOID ThreadMainProc(L_VOID *dummy) { #ifdef UNICODE struct _wfinddata_t fileinfo; #else struct _finddata_t fileinfo; #endif L_TCHAR *lp; L_TCHAR thisfile[_MAX_PATH]; long filehandle; L_INT nRet; ZeroMemory (&fileinfo,sizeof(fileinfo)); SetWindowText(hMainWnd, TEXT("Thread has been created")); L_InitBitmap(&ThreadBitmap, sizeof(BITMAPHANDLE), 1, 1, 1); /* prepare to go to the first file */ lstrcpy( thisfile, TEXT("(none)") ); /* obtain the directory name from the command line */ if( !*Data.szFilename ) lstrcpy(Data.szFilename, TEXT("*.*")); else { lp = Data.szFilename + lstrlen(Data.szFilename) - 1; if( *lp == '\\' ) *lp = 0; else lp++; _tchdir(Data.szFilename); lstrcpy(lp, TEXT("\\*.*") ); } if( (filehandle = _tfindfirst( Data.szFilename, &fileinfo)) != -1L ) do { if( WaitForSingleObject(hWindowTitleMutex,1000) == WAIT_OBJECT_0 ) { wsprintf(szWindowTitle, TEXT("%s - loading %s"), thisfile, fileinfo.name); ReleaseMutex(hWindowTitleMutex); PostMessage( hMainWnd, WM_COMMAND, IDM_SETWINDOWTITLE, 0 ); } /* load next file */ nRet = L_LoadBitmap( fileinfo.name, &ThreadBitmap, sizeof(BITMAPHANDLE), 0, ORDER_BGR, NULL, NULL); if( bKillThread ) { /* not interested in painting the images we just loaded - must quit */ if( nRet == SUCCESS ) L_FreeBitmap(&ThreadBitmap); break; } /* if load was successful, copy the new bitmap to the current bitmap */ if( nRet == SUCCESS ) { lstrcpy(thisfile, fileinfo.name ); if( WaitForSingleObject(hImagePaintedSemaphore, 40000) != WAIT_OBJECT_0 ) { MessageBox(NULL, TEXT("Error waiting for semaphore. Example terminated."), TEXT("Thread example"), MB_OK); L_FreeBitmap(&ThreadBitmap); break; } if( WaitForSingleObject(hBitmapMutex, 40000) != WAIT_OBJECT_0 ) { MessageBox(NULL, TEXT("Error waiting for mutex. Example terminated."), TEXT("Thread example"), MB_OK); L_FreeBitmap(&ThreadBitmap); break; } /* free the old bitmap data */ if( Data.BitmapHandle.Flags.Allocated ) L_FreeBitmap(&Data.BitmapHandle); if( Data.hPalette ) { DeleteObject( Data.hPalette ); Data.hPalette = NULL; } /* copy the bitmap data */ memcpy( &Data.BitmapHandle, &ThreadBitmap, sizeof(BITMAPHANDLE) ); /* release the mutex */ ReleaseMutex(hBitmapMutex); /* no more paints if I have to quit the program */ if( bKillThread ) break; /* reset the paint effect counter */ nClassEffect = 0; nPaintEffect = nEffectIndex[nClassEffect]; if(WaitForSingleObject(hWindowTitleMutex, 1000) == WAIT_OBJECT_0) { wsprintf(szWindowTitle, TEXT("Painting %s"), fileinfo.name); ReleaseMutex(hWindowTitleMutex); PostMessage(hMainWnd, WM_COMMAND, IDM_SETWINDOWTITLE, 0); } /* repaint the window */ PostMessage(hMainWnd, WM_COMMAND, IDM_REPAINTWINDOW, FALSE); } /* prepare to go to the next file. If there aren't any, quit */ if( _tfindnext(filehandle, &fileinfo) == -1 ) break; } while( !bKillThread ); else MessageBox(hMainWnd, Data.szFilename, TEXT("No files found!"), MB_OK|MB_ICONERROR); /* mark the thread as being killed */ lThread = 0; if( bKillThread ) PostMessage(hMainWnd, WM_COMMAND, IDM_DESTROYWINDOW, FALSE); else if( WaitForSingleObject(hWindowTitleMutex,1000) == WAIT_OBJECT_0 ) { wsprintf(szWindowTitle, TEXT("No more files. Example is complete.")); ReleaseMutex(hWindowTitleMutex); PostMessage( hMainWnd, WM_COMMAND, IDM_SETWINDOWTITLE, 0 ); } } /*---[ExtractCommandData]---------------------------------------------------- Syntax: L_BOOL ExtractCommandData( ); Parameters: None. ProtoType: Thread.c Notes: - This procedure is responsible for extracting the file name passed through the command line. - You should call this function only in WinMain function. --------------------------------------------------------------------------*/ L_BOOL ExtractCommandData ( ) { LPTSTR pszFirst = NULL; LPTSTR pszCmdLine = NULL; LPTSTR psz = NULL; L_INT nFirstPos = 0 ; L_INT nStringLen = 0 ; pszCmdLine = GetCommandLine(); nStringLen = lstrlen ( pszCmdLine ) + 1 ; // To specify that it is command line or not. if(( pszCmdLine[1] == ':' ) || // Shortcut case ( pszCmdLine[2] == ':' )) //VS case { // 1- TRY TO EXPOSE THE EXE NAME FROM THE COMMAND LINE psz = _tcschr ( pszCmdLine, ':' ) ; if ( NULL == psz ) { return FALSE ; } } else { psz = pszCmdLine ; } pszFirst = _tcschr ( psz + 1, ':' ) ; if ( NULL == pszFirst ) { return FALSE ; } // Calc the char number to the image file name. nFirstPos = pszFirst - pszCmdLine - 1 ; if ( 0 > nFirstPos ) { return FALSE ; } memset ( Data.szFilename, 0, sizeof ( Data.szFilename ) ); lstrcpyn ( Data.szFilename, pszFirst - 1, ( nStringLen - nFirstPos ) ) ; return TRUE; }