Thread: How can I draw directly on the Desktop?

  1. #1
    Registered User HelpfulPerson's Avatar
    Join Date
    Jun 2013
    Location
    Over the rainbow
    Posts
    288

    How can I draw directly on the Desktop?

    I've done my research on this, and discovered that my two options are either to hook into the explorer.exe process or create a transparent window. I'd rather not create a transparent window, because I'm doing this for fun and to learn more about .DLL functionality. That being said, although I understand the MSDN documentation of the SetWindowHookEx() function, I'm not exactly sure of the lineage of what I need to do. The main part that I'm not sure about is creating a .DLL, unless I'm just creating a .DLL that would hook into a specific function that updates the screen. Even so, I don't see the point in doing that. If my understanding is correct, I would need to save my drawing objects and just update them when the application I hooked into receives a WM_PAINT/WM_ERASEBKGND message. I would appreciate if someone cleared up the exact line of calls and code I need to make.
    "Some people think they can outsmart me, maybe. Maybe. I've yet to meet one that can outsmart bullet" - Meet the Heavy, Team Fortress 2

  2. #2
    11DE784A SirPrattlepod's Avatar
    Join Date
    Aug 2013
    Posts
    485
    Don't do this. I'll tell you a story.

    In my first year of school I was intently listening to the teacher sitting at my desk near the front of the class. I'm pretty sure that the previous week I'd been in the special box at the front so that other students couldn't see me because apparently I distracted them, but I digress. Anyway I'd been let out of my box and was listening itently to what the teacher had to say. I was in the front row of desks so I couldn't look at other students to distract them. Anyway, I was so absorbed in what the teacher was telling me I was holding my pencil and running it back and forth around on the desk, thinking that it was pointy side up (so it shouldn't have been drawing). Suddenly the teacher yelled at me! "What the ....?" I thought, bewildered. She pointed at my desk and my eyes slowly looked downwards. To my absolute horror and dismay somehow the orientation of the pencil had flipped and the pointy side was down, drawing all over the desk! The teacher didn't believe me when I said it was an accident (it truly was... it was most definitely an orientation error only).

    I got sent to the headmasters office. I'd never been inside the inner sanctum of the offices before and I was quite literally trembling in fear. The headmaster was away (I think he'd had a heart attack or something) so when I was led into his throne room it was the assistant principal who sat behind the desk, glowering at me with evil eyes almost hidden by his large grey eyebrows which looked a bit like insect cocoons. Umm, where was I? Oh yes, he glowered at me. Then SLAMMED this big thick leather strap against his desk, shaking the very foundations of the building; books fell off the cupboards and papers flew into the air to lazily fall back to earth, settling around the room like very large snowflakes. Needless to say I was terrified and began crying uncontrollably. My grief and terror were so intense that they had to call my mother to take me home.

    The moral of the story? If you draw on your desktop, nobody will believe that it was an accident and you'll be scarred for life and turn out like me.

  3. #3
    Registered User
    Join Date
    Oct 2013
    Posts
    12
    SirPrattlepod, I'm afraid you didn't understand the question correctly lol

  4. #4
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Quote Originally Posted by HelpfulPerson View Post
    I've done my research on this, and discovered that my two options are either to hook into the explorer.exe process or create a transparent window. I'd rather not create a transparent window, because I'm doing this for fun and to learn more about .DLL functionality. That being said, although I understand the MSDN documentation of the SetWindowHookEx() function, I'm not exactly sure of the lineage of what I need to do. The main part that I'm not sure about is creating a .DLL, unless I'm just creating a .DLL that would hook into a specific function that updates the screen. Even so, I don't see the point in doing that. If my understanding is correct, I would need to save my drawing objects and just update them when the application I hooked into receives a WM_PAINT/WM_ERASEBKGND message. I would appreciate if someone cleared up the exact line of calls and code I need to make.
    It's been a good long while since I've done any Win32 GDI, but I do remember being able to do this by simply grabbing a NULL device context (ie: GetDC(NULL)) and drawing to it. Worked back then, no idea if it works on current Windows machines though...
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  5. #5
    Registered User HelpfulPerson's Avatar
    Join Date
    Jun 2013
    Location
    Over the rainbow
    Posts
    288
    Quote Originally Posted by Sebastiani View Post
    It's been a good long while since I've done any Win32 GDI, but I do remember being able to do this by simply grabbing a NULL device context (ie: GetDC(NULL)) and drawing to it. Worked back then, no idea if it works on current Windows machines though...
    I've done that too, I created an SDL GUI to display pixels where the mouse cursor is on the screen, but I ran into lots of problems with it. First, SDL isn't exactly ideal since when it loses focus it no longer recieves events. Second, even with constantly getting the mouse cursor position eventually the code to get the pixel glitched up and the whole application broke for some reason. Which I end up having to restart it to fix it. I'm not sure if the cause is because the device context doesn't stay updated with the screen or if it's because of me closing and opening applications. Then, when I did research on it, apparently you have to constantly update the drawing you made for it to stick on the screen. It makes sense because it probably updates just like any SDL GUI I've made. My problem is, I've never done GDI before and just recently got interested in trying to do something in it. As I said, I'm confused to how to hook into explorer.exe ( e.g Do I make my own .DLL file?, How do I call it?, Do I need to do anything else to save the user's drawing on the screen? ). I'm hoping someone will know more about this than I do.

    Edit : SirPrattlepod, your story was hilarious
    Last edited by HelpfulPerson; 10-24-2013 at 06:35 PM.
    "Some people think they can outsmart me, maybe. Maybe. I've yet to meet one that can outsmart bullet" - Meet the Heavy, Team Fortress 2

  6. #6
    Registered User HelpfulPerson's Avatar
    Join Date
    Jun 2013
    Location
    Over the rainbow
    Posts
    288
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <math.h>
    
    
    #include <windows.h>
    
    
    #define VKEY_IS_PRESSED(vk)    ( GetAsyncKeyState(vk) & 0x8000 )
    
    
    enum
    {
        TIMER_START,
        TIMER_STOP,
        TIMER_GETDIFF
    };
    
    
    typedef struct t_timer
    {
        clock_t start_time;
        clock_t end_time;
    } t_timer;
    
    
    clock_t timer( int command, t_timer * timer1 )
    {
        switch ( command )
        {
            case TIMER_START :
                timer1->start_time = clock( );
            break;
    
    
            case TIMER_STOP :
                timer1->end_time = clock( );
            break;
    
    
            case TIMER_GETDIFF :
                return ( ( timer1->end_time - timer1->start_time ) / ( CLOCKS_PER_SEC / 1000 ));
            break;
    
    
            default : break;
        }
    
    
        return -1;
    }
    
    
    void win_error( char * message, BOOL exit )
    {
        char buffer[BUFSIZ] = { 0 };
        DWORD error_code = GetLastError( );
    
    
        FormatMessage
        (
            FORMAT_MESSAGE_FROM_SYSTEM,
            NULL,
            error_code,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR) buffer,
            BUFSIZ,
            NULL
        );
    
    
        MessageBox(NULL, buffer, message, MB_ICONWARNING | MB_OK );
    
    
        if ( exit ) ExitProcess( error_code );
    
    
        return;
    }
    
    
    void draw_box( COLORREF color, int x, int y, int w, int h )
    {
        RECT box_shape = { x, y, x + w, y + h };
        HDC device_context = GetDC( NULL );
        HBRUSH brush = 0;
    
    
    
    
        if ( !( brush = CreateSolidBrush( color ) ) )
        {
            win_error( "CreateSolidBrush( )", FALSE );
            return;
        }
    
    
        if ( !( FillRect( device_context, &box_shape, brush ) ) )
        {
            win_error( "FillRgn( )", FALSE );
            return;
        }
    
    
        if ( !( DeleteObject( brush ) ) )
        {
            win_error( "DeleteObject( )", FALSE );
            return;
        }
    
    
        ReleaseDC( NULL, device_context );
    
    
        return;
    }
    
    
    int main( )
    {
        HDC screen_context = GetDC( NULL );
        POINT pos1 = { 0 }, pos2 = { 0 };
        POINT mouse_cursor_pos = { 0 };
        COLORREF color = { 0 };
        size_t brush_size = 25;
    
    
        for ( ; ; )
        {
            GetCursorPos( &mouse_cursor_pos );
    
    
            if ( VKEY_IS_PRESSED( VK_ESCAPE ) )
                break;
    
    
            if ( VKEY_IS_PRESSED( VK_LBUTTON ) )
                color = GetPixel( screen_context, mouse_cursor_pos.x, mouse_cursor_pos.y );
            if ( VKEY_IS_PRESSED( VK_UP ) )
                draw_box( color, mouse_cursor_pos.x, mouse_cursor_pos.y, brush_size, brush_size );
            if ( VKEY_IS_PRESSED( VK_LEFT ) )
                pos1 = mouse_cursor_pos;
            if ( VKEY_IS_PRESSED( VK_RIGHT ) )
                pos2 = mouse_cursor_pos;
    
    
            if ( VKEY_IS_PRESSED( VK_SPACE ) )
                if ( pos1.x && pos1.y && pos2.x && pos2.y )
                    draw_box( color, pos1.x, pos1.y, fabs( pos2.x - pos1.x ), fabs( pos2.y - pos1.y ) );
    
    
            if ( VKEY_IS_PRESSED( VK_ADD ) )
                brush_size += 5;
            if ( VKEY_IS_PRESSED( VK_SUBTRACT ) )
                brush_size = fabs( brush_size - 5 );
    
    
            Sleep( 20 );
        }
    
    
        ReleaseDC( NULL, screen_context );
    
    
        return 0;
    }
    The program I made above works, but any slight update to the screen clears out any drawing I did.
    "Some people think they can outsmart me, maybe. Maybe. I've yet to meet one that can outsmart bullet" - Meet the Heavy, Team Fortress 2

  7. #7
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Well, you probably need to set up a message loop to process things like WM_ERASEBKGND, to begin with.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  8. #8
    Registered User
    Join Date
    Jan 2009
    Location
    Australia
    Posts
    375
    I spent quite a while trying to experiment with this sort of thing a few years ago.

    I just did some digging and found the code, it's for Windows XP no idea if it will work on anything else.

    From the looks of it it seems that on Windows XP you can get the HDC of the display with disp = CreateDC( "DISPLAY", NULL, NULL, NULL );.

    This won't compile btw because it's missing the resource file and stuff, but it's pretty simple so it might give you ideas. Sorry for the code quality it's from years ago and I was never really good with Windows API anyways. Looks like the most relevant code is in WM_TIMER, knock yourself out.

    Code:
    /*A desktop draw POC*/
    
    #include <windows.h>
    #include "DeskDraw.h"
    
    int CurrentSelected = MOUSESELECT;
    
    HINSTANCE AppInstance;
    int MidPressed = NOTPRESSED;
    
    HBITMAP Pens;
    HBITMAP PensSel;
    HCURSOR SystemCursor, CpySystemCursor;
    
    
    void DrawButtons( HWND WndHwnd )
    {
        HDC whDC, NewDC;
    
        whDC = GetDC( WndHwnd );
        NewDC = CreateCompatibleDC( whDC );
    
        SelectObject( NewDC, Pens );
    
        if( !BitBlt( whDC, 0, 0, 150, 50, NewDC, 0, 0, SRCCOPY ))
        {
            MessageBox( NULL, "Failed to Blit src to dest", "Failed", MB_OK );
        }
    
        SelectObject( NewDC, PensSel );
    
        BitBlt( whDC, CurrentSelected * 50, 0, 50, 50, NewDC, CurrentSelected * 50, 0, SRCCOPY );
    
        DeleteDC( NewDC );
        DeleteDC( whDC );
    }
    
    LRESULT CALLBACK WndProc( HWND WndHwnd, UINT Msg, WPARAM wParam, LPARAM lParam )
    {
        static HDC disp;
        SHORT MidKeyState = 0;
        POINT mousepos;
        int penstyle, width;
        COLORREF PenCol;
    
        switch( Msg )
        {
            case WM_CREATE:
                SetTimer( WndHwnd, 1, 80, NULL );
                disp = CreateDC( "DISPLAY", NULL, NULL, NULL );
    
                Pens = LoadBitmap( AppInstance, "PENS1" );
                PensSel = LoadBitmap( AppInstance, "PENSPUSHED2" );
    
                if( Pens == NULL || PensSel == NULL )
                {
                    MessageBox( NULL, "Could not load Bitmaps", "Failed", MB_OK );
                    DestroyWindow( WndHwnd );
                }
    
                SystemCursor = LoadCursor( NULL, IDC_ARROW );
                CpySystemCursor = CopyCursor( SystemCursor );
                DestroyCursor( SystemCursor );
                break;
    
            case WM_TIMER:
                if( CurrentSelected != MOUSESELECT )
                {
                    if( !MidPressed )
                    {
                        GetCursorPos( &mousepos );
                        MoveToEx( disp, mousepos.x, mousepos.y, NULL );
                        DrawButtons( WndHwnd );
                        UpdateWindow( WndHwnd );
                    }
                    if( (MidKeyState = GetAsyncKeyState( VK_MBUTTON )) != 0 )
                    {
                        MidPressed = PRESSED;
                        if( MidKeyState & 1 )
                        {
                            //If Mid mouse pressed since last call
                            GetCursorPos( &mousepos );
                            MoveToEx( disp, mousepos.x, mousepos.y, NULL );
                        }
    
                        else
                        {
                            GetCursorPos( &mousepos );
                            LineTo( disp, mousepos.x, mousepos.y );
                        }
                    }
                }
                break;
    
            case WM_LBUTTONDOWN:
                if( (lParam & 0xFFFF ) < 50 )
                {
                    SystemCursor = CopyCursor( CpySystemCursor );
                    SetSystemCursor( CpySystemCursor, OCR_NORMAL );
                    CpySystemCursor = CopyCursor( SystemCursor );
                    DestroyCursor( SystemCursor );
    
                    PenCol = 0;
                    CurrentSelected = MOUSESELECT;
                }
                else if( (lParam & 0xFFFF ) < 100 )
                {
                    SetSystemCursor( LoadCursor( AppInstance, "BLUECUR" ), OCR_NORMAL );
    
                    PenCol = (0xFF << 16);
                    CurrentSelected = BLUESELECT;
                }
                else
                {
                    SetSystemCursor( LoadCursor( AppInstance, "REDCUR" ), OCR_NORMAL );
    
                    PenCol = 0xFF;
                    CurrentSelected = REDSELECT;
                }
    
                penstyle = PS_SOLID;
                width = 2;
    
                SelectObject( disp, CreatePen( penstyle, width, PenCol ) );
    
                DrawButtons( WndHwnd );
                UpdateWindow( WndHwnd );
                break;
    
            case WM_MOVE:
                DrawButtons( WndHwnd );
                UpdateWindow( WndHwnd );
                break;
    
            case WM_CLOSE:
                DestroyWindow( WndHwnd );
                break;
    
            case WM_DESTROY:
                KillTimer( WndHwnd, 1 );
                DeleteDC( disp );
                DeleteObject( Pens );
                DeleteObject( PensSel );
                SetSystemCursor( CpySystemCursor, OCR_NORMAL );
                DestroyCursor( CpySystemCursor );
                PostQuitMessage( 0 );
                break;
    
            default:
                return DefWindowProc( WndHwnd, Msg, wParam, lParam );
                break;
        }
        return 0;
    }
    
    
    int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR CmdArgs, int nCmdShow )
    {
        WNDCLASSEX WndCls;
        HWND WndHwnd;
        MSG Msg;
        int captionh, borderw;
    
        AppInstance = hInstance;
    
        WndCls.cbSize = sizeof( WNDCLASSEX );
        WndCls.style = 0;
        WndCls.lpfnWndProc = WndProc;
        WndCls.cbClsExtra = 0;
        WndCls.cbWndExtra = 0;
        WndCls.hInstance = hInstance;
        WndCls.hIcon = LoadIcon( hInstance, "APPICON" );
        WndCls.hCursor = LoadCursor( NULL, IDC_ARROW );
        WndCls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        WndCls.lpszMenuName = NULL;
        WndCls.lpszClassName = "NewClass";
        WndCls.hIconSm = NULL;
    
        if( !RegisterClassEx( &WndCls ) )
        {
            MessageBox( NULL, "Class registration failed", "Failed", MB_OK );
            return 0;
        }
    
        captionh = GetSystemMetrics( SM_CYCAPTION );
        borderw = GetSystemMetrics( SM_CXBORDER );
    
        WndHwnd = CreateWindowEx( WS_EX_TOPMOST, "NewClass", "ToolBox", WS_SYSMENU, 0, 0, borderw * 2 + 150, captionh + borderw * 2 + 50, NULL, NULL, hInstance, NULL );
    
        if( WndHwnd == NULL )
        {
            MessageBox( NULL, "Could not create window", "Failed", MB_OK );
            UnregisterClass( "NewClass", hInstance );
            return 0;
        }
    
        ShowWindow( WndHwnd, SW_SHOW );
        UpdateWindow( WndHwnd );
    
        while( GetMessage( &Msg, WndHwnd, 0, 0 ) > 0 )
        {
            TranslateMessage( &Msg );
            DispatchMessage( &Msg );
        }
        UnregisterClass( "NewClass", hInstance );
        return 0;
    }
    Last edited by DeadPlanet; 10-27-2013 at 07:08 AM.

  9. #9
    Registered User HelpfulPerson's Avatar
    Join Date
    Jun 2013
    Location
    Over the rainbow
    Posts
    288
    Quote Originally Posted by DeadPlanet View Post
    I spent quite a while trying to experiment with this sort of thing a few years ago.

    I just did some digging and found the code, it's for Windows XP no idea if it will work on anything else.

    From the looks of it it seems that on Windows XP you can get the HDC of the display with disp = CreateDC( "DISPLAY", NULL, NULL, NULL );.

    This won't compile btw because it's missing the resource file and stuff, but it's pretty simple so it might give you ideas. Sorry for the code quality it's from years ago and I was never really good with Windows API anyways. Looks like the most relevant code is in WM_TIMER, knock yourself out.

    Code:
    /*A desktop draw POC*/
    
    #include <windows.h>
    #include "DeskDraw.h"
    
    int CurrentSelected = MOUSESELECT;
    
    HINSTANCE AppInstance;
    int MidPressed = NOTPRESSED;
    
    HBITMAP Pens;
    HBITMAP PensSel;
    HCURSOR SystemCursor, CpySystemCursor;
    
    
    void DrawButtons( HWND WndHwnd )
    {
        HDC whDC, NewDC;
    
        whDC = GetDC( WndHwnd );
        NewDC = CreateCompatibleDC( whDC );
    
        SelectObject( NewDC, Pens );
    
        if( !BitBlt( whDC, 0, 0, 150, 50, NewDC, 0, 0, SRCCOPY ))
        {
            MessageBox( NULL, "Failed to Blit src to dest", "Failed", MB_OK );
        }
    
        SelectObject( NewDC, PensSel );
    
        BitBlt( whDC, CurrentSelected * 50, 0, 50, 50, NewDC, CurrentSelected * 50, 0, SRCCOPY );
    
        DeleteDC( NewDC );
        DeleteDC( whDC );
    }
    
    LRESULT CALLBACK WndProc( HWND WndHwnd, UINT Msg, WPARAM wParam, LPARAM lParam )
    {
        static HDC disp;
        SHORT MidKeyState = 0;
        POINT mousepos;
        int penstyle, width;
        COLORREF PenCol;
    
        switch( Msg )
        {
            case WM_CREATE:
                SetTimer( WndHwnd, 1, 80, NULL );
                disp = CreateDC( "DISPLAY", NULL, NULL, NULL );
    
                Pens = LoadBitmap( AppInstance, "PENS1" );
                PensSel = LoadBitmap( AppInstance, "PENSPUSHED2" );
    
                if( Pens == NULL || PensSel == NULL )
                {
                    MessageBox( NULL, "Could not load Bitmaps", "Failed", MB_OK );
                    DestroyWindow( WndHwnd );
                }
    
                SystemCursor = LoadCursor( NULL, IDC_ARROW );
                CpySystemCursor = CopyCursor( SystemCursor );
                DestroyCursor( SystemCursor );
                break;
    
            case WM_TIMER:
                if( CurrentSelected != MOUSESELECT )
                {
                    if( !MidPressed )
                    {
                        GetCursorPos( &mousepos );
                        MoveToEx( disp, mousepos.x, mousepos.y, NULL );
                        DrawButtons( WndHwnd );
                        UpdateWindow( WndHwnd );
                    }
                    if( (MidKeyState = GetAsyncKeyState( VK_MBUTTON )) != 0 )
                    {
                        MidPressed = PRESSED;
                        if( MidKeyState & 1 )
                        {
                            //If Mid mouse pressed since last call
                            GetCursorPos( &mousepos );
                            MoveToEx( disp, mousepos.x, mousepos.y, NULL );
                        }
    
                        else
                        {
                            GetCursorPos( &mousepos );
                            LineTo( disp, mousepos.x, mousepos.y );
                        }
                    }
                }
                break;
    
            case WM_LBUTTONDOWN:
                if( (lParam & 0xFFFF ) < 50 )
                {
                    SystemCursor = CopyCursor( CpySystemCursor );
                    SetSystemCursor( CpySystemCursor, OCR_NORMAL );
                    CpySystemCursor = CopyCursor( SystemCursor );
                    DestroyCursor( SystemCursor );
    
                    PenCol = 0;
                    CurrentSelected = MOUSESELECT;
                }
                else if( (lParam & 0xFFFF ) < 100 )
                {
                    SetSystemCursor( LoadCursor( AppInstance, "BLUECUR" ), OCR_NORMAL );
    
                    PenCol = (0xFF << 16);
                    CurrentSelected = BLUESELECT;
                }
                else
                {
                    SetSystemCursor( LoadCursor( AppInstance, "REDCUR" ), OCR_NORMAL );
    
                    PenCol = 0xFF;
                    CurrentSelected = REDSELECT;
                }
    
                penstyle = PS_SOLID;
                width = 2;
    
                SelectObject( disp, CreatePen( penstyle, width, PenCol ) );
    
                DrawButtons( WndHwnd );
                UpdateWindow( WndHwnd );
                break;
    
            case WM_MOVE:
                DrawButtons( WndHwnd );
                UpdateWindow( WndHwnd );
                break;
    
            case WM_CLOSE:
                DestroyWindow( WndHwnd );
                break;
    
            case WM_DESTROY:
                KillTimer( WndHwnd, 1 );
                DeleteDC( disp );
                DeleteObject( Pens );
                DeleteObject( PensSel );
                SetSystemCursor( CpySystemCursor, OCR_NORMAL );
                DestroyCursor( CpySystemCursor );
                PostQuitMessage( 0 );
                break;
    
            default:
                return DefWindowProc( WndHwnd, Msg, wParam, lParam );
                break;
        }
        return 0;
    }
    
    
    int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR CmdArgs, int nCmdShow )
    {
        WNDCLASSEX WndCls;
        HWND WndHwnd;
        MSG Msg;
        int captionh, borderw;
    
        AppInstance = hInstance;
    
        WndCls.cbSize = sizeof( WNDCLASSEX );
        WndCls.style = 0;
        WndCls.lpfnWndProc = WndProc;
        WndCls.cbClsExtra = 0;
        WndCls.cbWndExtra = 0;
        WndCls.hInstance = hInstance;
        WndCls.hIcon = LoadIcon( hInstance, "APPICON" );
        WndCls.hCursor = LoadCursor( NULL, IDC_ARROW );
        WndCls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        WndCls.lpszMenuName = NULL;
        WndCls.lpszClassName = "NewClass";
        WndCls.hIconSm = NULL;
    
        if( !RegisterClassEx( &WndCls ) )
        {
            MessageBox( NULL, "Class registration failed", "Failed", MB_OK );
            return 0;
        }
    
        captionh = GetSystemMetrics( SM_CYCAPTION );
        borderw = GetSystemMetrics( SM_CXBORDER );
    
        WndHwnd = CreateWindowEx( WS_EX_TOPMOST, "NewClass", "ToolBox", WS_SYSMENU, 0, 0, borderw * 2 + 150, captionh + borderw * 2 + 50, NULL, NULL, hInstance, NULL );
    
        if( WndHwnd == NULL )
        {
            MessageBox( NULL, "Could not create window", "Failed", MB_OK );
            UnregisterClass( "NewClass", hInstance );
            return 0;
        }
    
        ShowWindow( WndHwnd, SW_SHOW );
        UpdateWindow( WndHwnd );
    
        while( GetMessage( &Msg, WndHwnd, 0, 0 ) > 0 )
        {
            TranslateMessage( &Msg );
            DispatchMessage( &Msg );
        }
        UnregisterClass( "NewClass", hInstance );
        return 0;
    }
    Thanks, I'll definitely play around with it some. I've never personally messed with Windows GUI objects, so it will be nice to use that code to set up a base for learning. I hope I can learn more about the WinAPI from it.
    "Some people think they can outsmart me, maybe. Maybe. I've yet to meet one that can outsmart bullet" - Meet the Heavy, Team Fortress 2

  10. #10
    Registered User
    Join Date
    Jan 2009
    Location
    Australia
    Posts
    375
    If you need help getting a running version going just shoot me a message. Looking at it now I remember most of what is going on.

  11. #11
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    t is not easy or advisable to draw directly to the desktop, as this tends to annoy users and to slow down windows. Not to mention that the desktop screen changes, as apps start, move close, etc.

    I suggest you first create an app that allows you to draw on its window and make your drawing persist (even when another window covers yours).

    Once you have that then you can consider making it draw to the desktop.

    Transparent Bitmaps

    >>The program I made above works, but any slight update to the screen clears out any drawing I did.

    You need a 'back buffer'.

    You 'save' all your drawing to this back buffer.

    This is a compatible DC with a compatible bitmap the same size as the whole screen.

    When you get a message that requires some drawing, you draw to the back buffer, then copy (bitblt) the back buffer to a copy of the screen DC and then generate a paint message.

    In the paint handler you bitblt the minimum area to the screen (not the whole screen everytime as most new coders do).

    >>CreateDC( "DISPLAY", NULL, NULL, NULL );.

    This is the same as GetDC(NULL), except you DeleteDC() if you 'create' and ReleaseDC() if you 'get'.

    Rememeber you need to save the return from SelectObject() so you can put the DC back to its default state prior to calling DeleteDC().

    ie when you CreateCompatibleDC() it already contains a set of default GDI objects (pen, brush, font, etc) and a 1x1 monochrome bitmap.
    A GDI object may not delete if it is currently selected into a DC, (this is why you other app probably crashed, as it ran your PC out of GDI memory).

    You can view the GDI objects an app is using in TaskManager (View -> Select Columns and add 'GDI Objects')
    Last edited by novacain; 10-30-2013 at 02:10 AM.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. can copy directly???
    By nurulhafiz in forum C Programming
    Replies: 4
    Last Post: 09-26-2006, 02:09 PM
  2. Boot Directly into c++ program
    By Cgawd in forum A Brief History of Cprogramming.com
    Replies: 4
    Last Post: 10-21-2002, 04:15 PM
  3. Storing a bitmap directly in cpp
    By MrWizard in forum Windows Programming
    Replies: 9
    Last Post: 04-10-2002, 10:49 AM
  4. Write directly to the screen?
    By SMurf in forum Windows Programming
    Replies: 0
    Last Post: 01-24-2002, 07:40 AM
  5. Accessing memory directly
    By YALINI in forum C Programming
    Replies: 0
    Last Post: 08-30-2001, 11:56 PM