Results 1 to 13 of 13

Thread: Win32 Colored, Bordered, Titlebarless Window

  1. #1
    Join Date
    Dec 2006
    Location
    Banville
    Posts
    3,914
    Mentioned
    12 Post(s)
    Quoted
    98 Post(s)

    Default Win32 Colored, Bordered, Titlebarless Window

    Note the blue border and the white bar at the top. I expected the window to be a solid color - the white bar at the top seems to be the remnants of the title bar, which shouldn't be drawn based on my call to SetWindowLongPtr. I think I can work around this by painting the entire window surface directly, but want an OS-mediated solution if at all possible.

    Window.PNG

    Code:
    x86_64-w64-mingw32-g++ -municode -Wno-write-strings Dummy.cpp -o Dummy.exe -lgdi32
    Code:
    #define _UNICODE
    
    #include <tchar.h>
    #include <Windows.h>
    #include <strsafe.h>
    
    LRESULT CALLBACK WndProc(
    	_In_ HWND	hWnd,
    	_In_ UINT	message,
    	_In_ WPARAM	wParam,
    	_In_ LPARAM	lParam
    );
    
    void ErrorExit(
    	LPTSTR lpszFunction
    );
    
    HINSTANCE hInst;
    WCHAR szTitle[] = TEXT("Dummy");
    WCHAR szMenuName[] = TEXT("Dummy");
    WCHAR szWindowClass[] = TEXT("Dummy");
    
    int APIENTRY
    wWinMain(
    	_In_	 HINSTANCE	hInstance,
    	_In_opt_ HINSTANCE	hPrevInstance,
    	_In_	 LPWSTR		lpCmdLine,
    	_In_ 	 int		nCmdShow
    )
    {
    	LPWSTR *szArgList;
    	int narg;
    	WNDCLASSEXW wcex;
    	HWND hWnd;
    	HACCEL hAccelTable;
    	MSG msg;
    	FILE *fConsole;
    
    	UNREFERENCED_PARAMETER(hPrevInstance);
    
    	szArgList = CommandLineToArgvW(GetCommandLineW(), &narg);
    	if (!szArgList) {
    		ErrorExit(L"CommandLineToArgvW");
    	}
    
    	// TODO: Add custom icon or use default Visual Studio icon.
    	wcex.cbSize			= sizeof(WNDCLASSEX);
    	wcex.style			= CS_HREDRAW | CS_VREDRAW;;
    	wcex.lpfnWndProc	= WndProc;
    	wcex.cbClsExtra		= 0;
    	wcex.cbWndExtra		= 0;
    	wcex.hInstance		= hInstance;
    	wcex.hIcon			= LoadIcon(hInstance, IDI_APPLICATION);
    	wcex.hCursor		= LoadCursor(nullptr, IDC_ARROW);
    	
    	if (narg > 1)
    		wcex.hbrBackground	= CreateSolidBrush(_wtoi(szArgList[1]));
    	else
    		wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW + 1);
    	
    	wcex.lpszMenuName	= szMenuName;
    	wcex.lpszClassName	= szWindowClass;
    	wcex.hIconSm		= LoadIcon(wcex.hInstance, IDI_APPLICATION);
    	if (!RegisterClassEx(&wcex)) {
    		ErrorExit(TEXT("RegisterClassExW"));
    	}
    
    	hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
    		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);
    	if (!hWnd) {
    		ErrorExit(TEXT("CreateWindowExW"));
    	}
    
    	if (!SetWindowLong(hWnd, GWL_STYLE, WS_BORDER | WS_THICKFRAME)) {
    		ErrorExit(TEXT("SetWindowLong"));
    	}
    
    	// Necessary per API reference for SetWindowLong. If left out,
    	// there will be a persistent rendering artifact after the first
    	// window move if the window has not been resized.
    	if (!SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED)) {
    		ErrorExit(TEXT("SetWindowPos"));
    	}
    	
    	ShowWindow(hWnd, nCmdShow);
    	if (!UpdateWindow(hWnd)) {
    		ErrorExit(TEXT("UpdateWindow"));
    	}
    	
    	hAccelTable = LoadAccelerators(hInstance, 0);
    	while (GetMessage(&msg, nullptr, 0, 0)) {
    		if (!TranslateAccelerator(hWnd, nullptr, &msg)) {
    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
    	}
    	
    	return (int)msg.wParam;
    }
    
    LRESULT CALLBACK
    WndProc(
    	_In_ HWND	hWnd,
    	_In_ UINT	message,
    	_In_ WPARAM	wParam,
    	_In_ LPARAM	lParam
    )
    {
    	switch (message) {
    	case WM_DESTROY: {
    		PostQuitMessage(0);
    		break;
    	}
    	default: {
    		return DefWindowProc(hWnd, message, wParam, lParam);
    	}
    	}
    	return 0;
    }
    
    void
    ErrorExit(
    	LPTSTR lpszFunction
    )
    {
    	// Retrieve the system error message for the last error code.
    	LPVOID lpMsgBuf;
    	LPVOID lpDisplayBuf;
    	DWORD lerr = GetLastError();
    	DWORD size = FormatMessage(
    		FORMAT_MESSAGE_ALLOCATE_BUFFER |
    		FORMAT_MESSAGE_FROM_SYSTEM |
    		FORMAT_MESSAGE_IGNORE_INSERTS,
    		NULL,
    		lerr,
    		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    		(LPTSTR)&lpMsgBuf,
    		0, NULL);
    
    	// Print the error message to the console.
    	//wprintf(TEXT("%s: %s"), lpszFunction, (wcharTEXT *)lpMsgBuf);
    
    	// Display the error message in a message box.
    	lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
    		(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
    	StringCchPrintf((LPTSTR)lpDisplayBuf,
    		LocalSize(lpDisplayBuf) / sizeof(TCHAR),
    		TEXT("%s failed with error %d: %s"),
    		lpszFunction, lerr, lpMsgBuf);
    	MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
    
    	LocalFree(lpMsgBuf);
    	ExitProcess(lerr);
    }
    Last edited by R0b0t1; 05-09-2017 at 10:52 PM.
    The jealous temper of mankind, ever more disposed to censure than
    to praise the work of others, has constantly made the pursuit of new
    methods and systems no less perilous than the search after unknown
    lands and seas.

  2. #2
    Join Date
    Dec 2010
    Posts
    483
    Mentioned
    30 Post(s)
    Quoted
    328 Post(s)

    Default

    One possible solution; a fullscreen transparent overlay window and just draw your actual window onto the surface.

    Here's the most professional example I could find:
    https://youtu.be/ND-aIhgL-nI?t=1m50s

    Fun little trick I'll add - you can manually pump form messages and keep the window responsive even when its doing nothing. All you really need to do is call PeekMessage at least once every few minutes to do this.

    Obviously the video is a joke; but this really is what you want to do.

    m_WndOverlay = CreateWindowEx(
    WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_LAYERED,
    #ifdef _UNICODE
    class_name.c_str(),
    window_title.c_str(),
    #else
    m_ClassName.c_str(),
    m_WindowTitle.c_str(),
    #endif
    WS_POPUP,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    windowWidth,
    windowHeight,
    nullptr,
    nullptr,
    nullptr,
    nullptr
    );

    This will create a transparent window, completely invisible to the user. It will also make it top most, then just draw the window design you want to it.

    Note2: Windows only. You won't find a platform independent solution to this I do not believe.

  3. #3
    Join Date
    Dec 2006
    Location
    Banville
    Posts
    3,914
    Mentioned
    12 Post(s)
    Quoted
    98 Post(s)

    Default

    Quote Originally Posted by the bank View Post
    One possible solution; a fullscreen transparent overlay window and just draw your actual window onto the surface.

    Here's the most professional example I could find:
    https://youtu.be/ND-aIhgL-nI?t=1m50s

    Fun little trick I'll add - you can manually pump form messages and keep the window responsive even when its doing nothing. All you really need to do is call PeekMessage at least once every few minutes to do this.

    Obviously the video is a joke; but this really is what you want to do.

    This will create a transparent window, completely invisible to the user. It will also make it top most, then just draw the window design you want to it.

    Note2: Windows only. You won't find a platform independent solution to this I do not believe.
    Why transparent? Why fullscreen? Is it not possible to draw over the title bar? As for keeping it topmost - I'm not sure I want that, but it was something I was going to need to think about eventually. What I want is to have a rectangle surrounded by a border.

    You (or someone else) might be able to comment on another issue I've had - if WS_THICKFRAME is left out then the window appears to be recessed into a very ugly looking border that is much thicker than the 1px Windows 10 border. Is there a way to draw the window rectangle with absolutely no border at all? In the case of a transparent window, is the border not also affected?

    And actually I just realized that it's not necessary to specify WS_BORDER at all, just WS_THICKFRAME.

    The title specifies Win32 - I don't expect any of this to be portable.
    Last edited by R0b0t1; 05-09-2017 at 10:24 PM.
    The jealous temper of mankind, ever more disposed to censure than
    to praise the work of others, has constantly made the pursuit of new
    methods and systems no less perilous than the search after unknown
    lands and seas.

  4. #4
    Join Date
    Dec 2010
    Posts
    483
    Mentioned
    30 Post(s)
    Quoted
    328 Post(s)

    Default

    Quote Originally Posted by R0b0t1 View Post
    Why transparent? Why fullscreen? Is it not possible to draw over the title bar? As for keeping it topmost - I'm not sure I want that, but it was something I was going to need to think about eventually. What I want is to have a rectangle surrounded by a border.

    You (or someone else) might be able to comment on another issue I've had - if WS_THICKFRAME is left out then the window appears to be recessed into a very ugly looking border that is much thicker than the 1px Windows 10 border. Is there a way to draw the window rectangle with absolutely no border at all? In the case of a transparent window, is the border not also affected?

    And actually I just realized that it's not necessary to specify WS_BORDER at all, just WS_THICKFRAME.

    The title specifies Win32 - I don't expect any of this to be portable.
    Sorry, perhaps I didn't fully understand you.

    You can use SetWindowLong to set a new window style.

    Code:
    SetWindowLong(hWnd, GWL_STYLE, WS_BORDER);
    Where hWnd is your handle to the window created with CreateWindow, GWL_STYLE specifies setting a new window style. Create your window with dwStyle equal to WS_BORDER, instead of WS_OVERLAPPEDWINDOW.

    If this still doesn't give you the results you're after, play around with SetWindowLong and different window styles to achieve what you're after.

    If it becomes more trouble than its worth to you, using a transparent overlay window (which has no border, by the way) you can just render the window however you want.

  5. #5
    Join Date
    Dec 2006
    Location
    Banville
    Posts
    3,914
    Mentioned
    12 Post(s)
    Quoted
    98 Post(s)

    Default

    Quote Originally Posted by the bank View Post
    Sorry, perhaps I didn't fully understand you.

    You can use SetWindowLong to set a new window style.

    Code:
    SetWindowLong(hWnd, GWL_STYLE, WS_BORDER);
    Where hWnd is your handle to the window created with CreateWindow, GWL_STYLE specifies setting a new window style. Create your window with dwStyle equal to WS_BORDER, instead of WS_OVERLAPPEDWINDOW.
    Per the code in my original post that's what I'm doing. I was just asking for an explanation as to why you suggested the things you did here.
    The jealous temper of mankind, ever more disposed to censure than
    to praise the work of others, has constantly made the pursuit of new
    methods and systems no less perilous than the search after unknown
    lands and seas.

  6. #6
    Join Date
    Dec 2010
    Posts
    483
    Mentioned
    30 Post(s)
    Quoted
    328 Post(s)

    Default

    Quote Originally Posted by R0b0t1 View Post
    Per the code in my original post that's what I'm doing. I was just asking for an explanation as to why you suggested the things you did here.
    As I said, that will create an invisible window, effectively acting as a drawing surface for you, of any dimensions you want. I was suggesting that perhaps you can draw your window onto such a thing manually, where you could include whatever type of border you wish.

    I then understood more clearly from your reply that I misunderstood your original goals.

    Let's try and get back on the same page. Your goal is a window that looks like what? What have you tried so far? What is still wrong with it?

  7. #7
    Join Date
    Dec 2006
    Location
    Banville
    Posts
    3,914
    Mentioned
    12 Post(s)
    Quoted
    98 Post(s)

    Default

    Quote Originally Posted by the bank View Post
    As I said, that will create an invisible window, effectively acting as a drawing surface for you, of any dimensions you want. I was suggesting that perhaps you can draw your window onto such a thing manually, where you could include whatever type of border you wish.

    I then understood more clearly from your reply that I misunderstood your original goals.

    Let's try and get back on the same page. Your goal is a window that looks like what? What have you tried so far? What is still wrong with it?
    I was wondering about the suggestion to make it fullscreen - that would require additional handling to make sure input is passed to other windows.

    I will try to make the window transparent and edit this post. Creating a (WS_SYSMENU or WS_POPUP) window should make it borderless, but this seems to not work in C++ on Windows 10.
    The jealous temper of mankind, ever more disposed to censure than
    to praise the work of others, has constantly made the pursuit of new
    methods and systems no less perilous than the search after unknown
    lands and seas.

  8. #8
    Join Date
    Dec 2010
    Posts
    483
    Mentioned
    30 Post(s)
    Quoted
    328 Post(s)

    Default

    Quote Originally Posted by R0b0t1 View Post
    I was wondering about the suggestion to make it fullscreen - that would require additional handling to make sure input is passed to other windows.

    I will try to make the window transparent and edit this post. Creating a (WS_SYSMENU or WS_POPUP) window should make it borderless, but this seems to not work in C++ on Windows 10.
    In the example I posted, input is ignored and transferred to the lower windows. It does not block input.

    You can thank WS_EX_LAYERED for that.

    But yeah, it doesn't have to be fullscreen. Only as large as the window you want, and will have to be programmatically moved with MoveWindow in that case.

    Remember - just turning the window transparent will only spawn an invisible window. You'll have to then draw the window design on yourself. This will however give you the most control possible in how your window looks.


    Also there's this on stack overflow, which looks a lot like what I mentioned in my second post; http://stackoverflow.com/questions/7...bar-with-win32 and people claim it removes both the title bar and border. I have not tried this personally.

  9. #9
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    I wrote a WinAPI Library years ago that makes these things easy.. I slimmed it down a LOT to make the example more compact..

    Anyway, the solution is to actually REMOVE the styles from the window and just set the extended edges as well as thick border. To remove the styles you must do bitwise operations..

    Example:
    C++ Code:
    int flag = WS_APPWINDOW | WS_THICKFRAME | WS_BLAHBLAH | WS_MEHMEH | WS_FOOFOO;

    flag &= ~WS_APPWINDOW; //Remove WS_APPWINDOW if and only if it is set.. equivalent to "flag = flag & ~WS_APPWINDOW".
    flag &= ~WS_BLAHBLAH; //Remove WS_BLAHBLAH
    flag &= ~(WS_MEHMEH | WS_FOOFOO);  //Remove both WS_MEHMEH and WS_FOOFOO..


    Using your code..
    C++ Code:
    #define _UNICODE
    #define UNICODE

    #include <tchar.h>
    #include <Windows.h>
    #include <strsafe.h>


    LRESULT CALLBACK WndProc(
        _In_ HWND   hWnd,
        _In_ UINT   message,
        _In_ WPARAM wParam,
        _In_ LPARAM lParam
    );

    void ErrorExit(
        LPTSTR lpszFunction
    );

    HINSTANCE hInst;
    WCHAR szTitle[] = TEXT("Dummy");
    WCHAR szMenuName[] = TEXT("Dummy");
    WCHAR szWindowClass[] = TEXT("Dummy");

    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
        LPWSTR *szArgList;
        int narg;
        WNDCLASSEXW wcex;
        HWND hWnd;
        HACCEL hAccelTable;
        MSG msg;
        FILE *fConsole;

        UNREFERENCED_PARAMETER(hPrevInstance);

        szArgList = CommandLineToArgvW(GetCommandLineW(), &narg);
        if (!szArgList) {
            ErrorExit(L"CommandLineToArgvW");
        }

        // TODO: Add custom icon or use default Visual Studio icon.
        wcex.cbSize         = sizeof(WNDCLASSEX);
        wcex.style          = CS_HREDRAW | CS_VREDRAW;;
        wcex.lpfnWndProc    = WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = hInstance;
        wcex.hIcon          = LoadIcon(hInstance, IDI_APPLICATION);
        wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);

        if (narg > 1)
            wcex.hbrBackground  = CreateSolidBrush(_wtoi(szArgList[1]));
        else
            wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);

        wcex.lpszMenuName   = szMenuName;
        wcex.lpszClassName  = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, IDI_APPLICATION);
        if (!RegisterClassEx(&wcex)) {
            ErrorExit(TEXT("RegisterClassExW"));
        }

        hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);
        if (!hWnd) {
            ErrorExit(TEXT("CreateWindowExW"));
        }



        LONG style = GetWindowLong(hWnd, GWL_STYLE);
        if (!SetWindowLong(hWnd, GWL_STYLE, (style & ~WS_OVERLAPPEDWINDOW) | WS_BORDER | WS_THICKFRAME)) {
            ErrorExit(TEXT("SetWindowLong"));
        }

        style = GetWindowLong(hWnd, GWL_EXSTYLE);
        if (!SetWindowLong(hWnd, GWL_EXSTYLE, style & ~WS_EX_CLIENTEDGE)) {
            ErrorExit(TEXT("SetWindowLong"));
        }

        // Necessary per API reference for SetWindowLong. If left out,
        // there will be a persistent rendering artifact after the first
        // window move if the window has not been resized.
        if (!SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED)) {
            ErrorExit(TEXT("SetWindowPos"));
        }

        ShowWindow(hWnd, nCmdShow);
        if (!UpdateWindow(hWnd)) {
            ErrorExit(TEXT("UpdateWindow"));
        }

        hAccelTable = LoadAccelerators(hInstance, 0);
        while (GetMessage(&msg, nullptr, 0, 0)) {
            if (!TranslateAccelerator(hWnd, nullptr, &msg)) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }

        return (int)msg.wParam;
    }

    LRESULT CALLBACK
    WndProc(
        _In_ HWND   hWnd,
        _In_ UINT   message,
        _In_ WPARAM wParam,
        _In_ LPARAM lParam
    )
    {
        switch (message) {
        case WM_DESTROY: {
            PostQuitMessage(0);
            break;
        }
        default: {
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        }
        return 0;
    }

    void
    ErrorExit(
        LPTSTR lpszFunction
    )
    {
        // Retrieve the system error message for the last error code.
        LPVOID lpMsgBuf;
        LPVOID lpDisplayBuf;
        DWORD lerr = GetLastError();
        DWORD size = FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            lerr,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR)&lpMsgBuf,
            0, NULL);

        // Print the error message to the console.
        //wprintf(TEXT("%s: %s"), lpszFunction, (wcharTEXT *)lpMsgBuf);

        // Display the error message in a message box.
        lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
            (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
        StringCchPrintf((LPTSTR)lpDisplayBuf,
            LocalSize(lpDisplayBuf) / sizeof(TCHAR),
            TEXT("%s failed with error %d: %s"),
            lpszFunction, lerr, lpMsgBuf);
        MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);

        LocalFree(lpMsgBuf);
        ExitProcess(lerr);
    }


    Using my code:
    C++ Code:
    #include <iostream>
    #include <windows.h>
    #include <functional>
    #include <vector>
    #include <cstdint>
    #include <tuple>
    #include <algorithm>



    /**
        Utilities
    **/

    #ifndef UNREFERENCED_PARAMETER
    #define UNREFERENCED_PARAMETER(P) {(P) = (P);}
    #endif // UNREFERENCED_PARAMETER

    enum class WindowStyle : std::uint32_t
    {
        NONE                                    = 0L,
        BORDER                                  = WS_BORDER,
        CHILD                                   = WS_CHILD,
        CLIPCHILDREN                            = WS_CLIPCHILDREN,
        CLIPSIBLINGS                            = WS_CLIPSIBLINGS,
        GROUP                                   = WS_GROUP,
        CAPTION                                 = WS_CAPTION,
        DISABLED                                = WS_DISABLED,
        DLGFRAME                                = WS_DLGFRAME,
        HSCROLL                                 = WS_HSCROLL,
        VSCROLL                                 = WS_VSCROLL,
        MINIMIZED                               = WS_MINIMIZE,
        MAXIMIZED                               = WS_MAXIMIZE,
        MAXIMIZE_BOX                            = WS_MAXIMIZEBOX,
        MINIMIZE_BOX                            = WS_MINIMIZEBOX,
        OVERLAPPED                              = WS_OVERLAPPED,
        OVERLAPPED_WINDOW                       = WS_OVERLAPPEDWINDOW,
        POPUP                                   = WS_POPUP,
        POPUP_WINDOW                            = WS_POPUPWINDOW,
        THICK_FRAME                             = WS_THICKFRAME,
        SYSMENU                                 = WS_SYSMENU,
        TABSTOP                                 = WS_TABSTOP,

        EX_ACCEPTFILES                          = WS_EX_ACCEPTFILES,
        EX_APPWINDOW                            = WS_EX_APPWINDOW,
        EX_CLIENTEDGE                           = WS_EX_CLIENTEDGE,
        EX_COMPOSITED                           = WS_EX_COMPOSITED,
        EX_CONTEXTHELP                          = WS_EX_CONTEXTHELP,
        EX_CONTROLPARENT                        = WS_EX_CONTROLPARENT,
        EX_DLGMODALFRAME                        = WS_EX_DLGMODALFRAME,
        EX_LAYERED                              = WS_EX_LAYERED,
        EX_LAYOUTRTL                            = WS_EX_LAYOUTRTL,
        EX_LEFT                                 = WS_EX_LEFT,
        EX_LEFTSCROLLBAR                        = WS_EX_LEFTSCROLLBAR,
        EX_LTRREADING                           = WS_EX_LTRREADING,
        EX_MDICHILD                             = WS_EX_MDICHILD,
        EX_NOACTIVATE                           = WS_EX_NOACTIVATE,
        EX_NOINHERITLAYOUT                      = WS_EX_NOINHERITLAYOUT,
        EX_NOPARENTNOTIFY                       = WS_EX_NOPARENTNOTIFY,
        EX_OVERLAPPEDWINDOW                     = WS_EX_OVERLAPPEDWINDOW,
        EX_PALETTEWINDOW                        = WS_EX_PALETTEWINDOW,
        EX_RIGHT                                = WS_EX_RIGHT,
        EX_RIGHTSCROLLBAR                       = WS_EX_RIGHTSCROLLBAR,
        EX_RTLREADING                           = WS_EX_RTLREADING,
        EX_STATICEDGE                           = WS_EX_STATICEDGE,
        EX_TOOLWINDOW                           = WS_EX_TOOLWINDOW,
        EX_TOPMOST                              = WS_EX_TOPMOST,
        EX_TRANSPARENT                          = WS_EX_TRANSPARENT,
        EX_WINDOWEDGE                           = WS_EX_WINDOWEDGE
    };

    inline WindowStyle operator ~ (WindowStyle a){return static_cast<WindowStyle>(~static_cast<std::uint32_t>(a));}
    inline WindowStyle operator | (WindowStyle a, WindowStyle b) {return static_cast<WindowStyle>(static_cast<std::uint32_t>(a) | static_cast<std::uint32_t>(b));}
    inline WindowStyle operator & (WindowStyle a, WindowStyle b) {return static_cast<WindowStyle>(static_cast<std::uint32_t>(a) & static_cast<std::uint32_t>(b));}

    void TrackMouse(HWND hwnd)
    {
        TRACKMOUSEEVENT tme;
        tme.cbSize = sizeof(TRACKMOUSEEVENT);
        tme.dwFlags = TME_HOVER | TME_LEAVE;
        tme.dwHoverTime = 1;
        tme.hwndTrack = hwnd;
        TrackMouseEvent(&tme);
    }

    void SetWindowTransparency(HWND hwnd, std::uint8_t Transperancy)
    {
        long wAttr = GetWindowLong(hwnd, GWL_EXSTYLE);
        SetWindowLong(hwnd, GWL_EXSTYLE, wAttr | WS_EX_LAYERED);
        SetLayeredWindowAttributes(hwnd, 0, Transperancy, 2);
    }

    void EnableVisualStyles()
    {
        wchar_t sys_dir[MAX_PATH] = {0};
        std::uint32_t len = GetSystemDirectoryW(sys_dir, sizeof(sys_dir) / sizeof(sys_dir[0]));
        if (len < sizeof(sys_dir) / sizeof(sys_dir[0]))
        {
            ACTCTXW actCtx =
            {
                sizeof(ACTCTX), ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_SET_PROCESS_DEFAULT |
                ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID, L"shell32.dll", 0, 0, sys_dir, reinterpret_cast<wchar_t*>(0x7C)
            };

            ULONG_PTR ulpActivationCookie = false;
            ActivateActCtx(CreateActCtxW(&actCtx), &ulpActivationCookie);
        }
    }

    void SetWindowStyle(HWND hwnd, WindowStyle style, bool remove_style = false)
    {
        LONG_PTR current_style = GetWindowLongPtr(hwnd, GWL_STYLE);
        SetWindowLongPtrW(hwnd, GWL_STYLE, remove_style ? (current_style & ~static_cast<std::uint32_t>(style)) : (current_style | static_cast<std::uint32_t>(style)));
        SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
    }

    void SetExtendedWindowStyle(HWND hwnd, WindowStyle style, bool remove_style = false)
    {
        LONG_PTR current_style = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
        SetWindowLongPtrW(hwnd, GWL_EXSTYLE, remove_style ? (current_style & ~static_cast<std::uint32_t>(style)) : (current_style | static_cast<std::uint32_t>(style)));
        SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
    }



    /**
        Class for storing events and invoking them..
    **/

    template<typename T>
    class EventManager;

    template<typename R, typename... Args>
    class EventManager<R(Args...)>
    {
        private:
            std::vector<std::tuple<std::uint64_t, std::uint64_t, std::function<R(Args...)>>> Events;

        public:
            std::uint64_t Subscribe(std::uint64_t Notification, std::function<R(Args...)>&& Func)
            {
                static std::uint64_t ID = 0;
                Events.emplace_back(std::make_tuple(!Notification ? 0 : ++ID, Notification, std::forward<std::function<R(Args...)>>(Func)));
                return ID;
            }

            void UnSubscribe(std::uint64_t EventID)
            {
                auto it = std::find_if(Events.begin(), Events.end(), [&](typename decltype(Events)::value_type &it) {
                    return std::get<0>(it) == EventID;
                });

                if (it != Events.end())
                {
                    Events.erase(it);
                }
            }

            bool Notify(std::uint64_t Notification, Args... args)
            {
                auto it = std::find_if(Events.begin(), Events.end(), [&](typename decltype(Events)::value_type &it) {
                    return std::get<1>(it) == Notification;
                });

                if (it != Events.end())
                {
                    std::get<2>(*it)(args...);
                    return true;
                }

                return false;
            }

            bool NotifyAll(std::uint64_t Notification, Args... args)
            {
                if (Notify(Notification, args...))
                {
                    return true;
                }

                auto it = std::find_if(Events.begin(), Events.end(), [&](typename decltype(Events)::value_type &it) {
                    return !std::get<1>(it);
                });

                if (it != Events.end())
                {
                    std::get<2>(*it)(args...);
                    return true;
                }

                return false;
            }
    };


    /**
        Class for creating Windows.
    **/


    class Form
    {
        public:
            Form(const wchar_t* Title, POINT Location, std::uint16_t Width, std::uint16_t Height, Form* Parent = nullptr);
            ~Form() {}

            Form(Form&& form) = delete;
            Form(const Form& form) = delete;
            Form& operator = (const Form& form) = delete;

            std::uint64_t AddListener(std::uint64_t Notification, std::function<void(UINT, WPARAM, LPARAM)>&& listener);
            void RemoveListener(std::uint64_t ID);

            void Center();

            int MessageLoop();
            void Close() {PostMessage(WindowHandle, WM_CLOSE, 0, 0);}
            void Dispose() {DestroyWindow(WindowHandle);}
            operator HWND() { return WindowHandle; }

        private:
            bool MouseTracking = false;
            HWND WindowHandle = nullptr;
            EventManager<void(UINT, WPARAM, LPARAM)> Events;

            LRESULT __stdcall HandleMessages(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam);
            static LRESULT __stdcall WindowProcedure(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam);
    };

    std::uint64_t Form::AddListener(std::uint64_t Notification, std::function<void(UINT, WPARAM, LPARAM)>&& listener)
    {
        return Events.Subscribe(Notification, std::forward<std::function<void(UINT, WPARAM, LPARAM)>>(listener));
    }

    void Form::RemoveListener(std::uint64_t Notification)
    {
        Events.UnSubscribe(Notification);
    }

    void Form::Center()
    {
        RECT rect = {0};
        RECT frame = {0};
        GetClientRect(GetDesktopWindow(), &rect);
        GetWindowRect(this->WindowHandle, &frame);
        int centerX = ((rect.right - rect.left) / 2) - ((frame.right - frame.left) / 2);
        int centerY = ((rect.bottom - rect.top) /2 ) - ((frame.bottom - frame.top) / 2);
        SetWindowPos(this->WindowHandle, nullptr, centerX, centerY, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
    }

    int Form::MessageLoop()
    {
        MSG Messages = {0};
        ShowWindow(WindowHandle, SW_SHOW);

        while(GetMessageW(&Messages, nullptr, 0, 0))
        {
            TranslateMessage(&Messages);
            DispatchMessageW(&Messages);
        }
        return Messages.wParam;
    }

    Form::Form(const wchar_t* Title, POINT Location, std::uint16_t Width, std::uint16_t Height, Form* Parent) : WindowHandle(nullptr)
    {
        WNDCLASSEXW WndClass =
        {
            sizeof(WNDCLASSEXW), CS_DBLCLKS, WindowProcedure,
            0, 0, GetModuleHandleW(nullptr), LoadIconW(nullptr, reinterpret_cast<wchar_t*>(IDI_APPLICATION)),
            LoadCursorW(nullptr, reinterpret_cast<wchar_t*>(IDC_ARROW)), HBRUSH(COLOR_BACKGROUND),
            nullptr, L"WIN_FORM_CLS", LoadIconW(nullptr, reinterpret_cast<wchar_t*>(IDI_APPLICATION))
        };

        RegisterClassExW(&WndClass);
        WindowHandle = CreateWindowExW(0, L"WIN_FORM_CLS", Title, WS_OVERLAPPEDWINDOW, Location.x, Location.y, Width, Height, Parent ? Parent->WindowHandle : nullptr, NULL, GetModuleHandleW(nullptr), this);
    }

    LRESULT __stdcall Form::HandleMessages(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
    {
        switch (Msg)
        {
            case WM_MOUSEMOVE:
            {
                if (!MouseTracking)
                {
                    TrackMouse(Hwnd);
                    MouseTracking = true;
                }
                Events.Notify(WM_MOUSEMOVE, Msg, wParam, lParam);
            }
            break;

            case WM_MOUSELEAVE:
            {
                MouseTracking = false;
                Events.Notify(WM_MOUSELEAVE, Msg, wParam, lParam);
            }
            break;

            case WM_MOUSEHOVER:
            {
                Events.Notify(WM_MOUSEHOVER, Msg, wParam, lParam);
            }
            break;

            case WM_CLOSE:
            {
                if (!Events.Notify(WM_CLOSE, Msg, wParam, lParam))
                {
                    return DefWindowProcW(Hwnd, Msg, wParam, lParam);
                }

                Events.NotifyAll(Msg, Msg, wParam, lParam);
            }
            break;

            case WM_DESTROY:
            {
                Events.Notify(WM_DESTROY, Msg, wParam, lParam);
                PostQuitMessage(0);
            }
            return 0;

            default:
            {
                Events.NotifyAll(Msg, Msg, wParam, lParam);
            }
            return DefWindowProcW(Hwnd, Msg, wParam, lParam);
        }
        return true;
    }

    LRESULT __stdcall Form::WindowProcedure(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
    {
        Form* frm = nullptr;

        switch(Msg)
        {
            case WM_NCCREATE:
            {
                CREATESTRUCTW* ptr = reinterpret_cast<CREATESTRUCTW*>(lParam);
                frm = reinterpret_cast<Form*>(ptr->lpCreateParams);
                SetWindowLongPtrW(Hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(frm));
                frm->WindowHandle = Hwnd;
                break;
            }

            case WM_DESTROY:
            {
                PostQuitMessage(0);
            }
            return 0;

            default:
            {
                frm = reinterpret_cast<Form*>(GetWindowLongPtrW(Hwnd, GWLP_USERDATA));
                break;
            }
        }

        return frm ? frm->HandleMessages(Hwnd, Msg, wParam, lParam) : DefWindowProcW(Hwnd, Msg, wParam, lParam);
    }


    int __stdcall WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
    {
        UNREFERENCED_PARAMETER(hThisInstance);
        UNREFERENCED_PARAMETER(hPrevInstance);
        UNREFERENCED_PARAMETER(lpszArgument);
        UNREFERENCED_PARAMETER(nCmdShow);


        EnableVisualStyles();
        Form Win(L"Window", {CW_USEDEFAULT, CW_USEDEFAULT}, 855, 470);
        SetWindowStyle(Win, WindowStyle::THICK_FRAME);
        SetWindowStyle(Win, WindowStyle::OVERLAPPED_WINDOW, true);
        SetExtendedWindowStyle(Win, WindowStyle::EX_CLIENTEDGE);

        Win.AddListener(WM_KEYDOWN, [&](UINT msg, WPARAM wp, LPARAM lp)
        {
            UNREFERENCED_PARAMETER(msg);
            UNREFERENCED_PARAMETER(wp);
            UNREFERENCED_PARAMETER(lp);

            if (wp == VK_ESCAPE)
            {
                Win.Close();
            }
        });

        Win.AddListener(WM_CLOSE, [&](UINT msg, WPARAM wp, LPARAM lp)
        {
            UNREFERENCED_PARAMETER(msg);
            UNREFERENCED_PARAMETER(wp);
            UNREFERENCED_PARAMETER(lp);

            Win.Dispose();
        });

        return Win.MessageLoop();
    }
    Last edited by Brandon; 05-10-2017 at 01:24 AM.
    I am Ggzz..
    Hackintosher

  10. #10
    Join Date
    Dec 2006
    Location
    Banville
    Posts
    3,914
    Mentioned
    12 Post(s)
    Quoted
    98 Post(s)

    Default

    Quote Originally Posted by the bank View Post
    In the example I posted, input is ignored and transferred to the lower windows. It does not block input.

    You can thank WS_EX_LAYERED for that.

    But yeah, it doesn't have to be fullscreen. Only as large as the window you want, and will have to be programmatically moved with MoveWindow in that case.

    Remember - just turning the window transparent will only spawn an invisible window. You'll have to then draw the window design on yourself. This will however give you the most control possible in how your window looks.


    Also there's this on stack overflow, which looks a lot like what I mentioned in my second post; http://stackoverflow.com/questions/7...bar-with-win32 and people claim it removes both the title bar and border. I have not tried this personally.
    That is one of the articles I was referring to. One of Olly's projects even has the code in it that they mention using WS_POPUP, and he claims it works. However, when I attempt to do that, the window never appears.

    See below for my attempt to do this with a transparent form - the title bar seems to appear. If I need to explicitly replace WM_PAINT then I suppose I can, it just seems kind of silly. Also - I would like to avoid repainting areas that the OS paints by itself. There may or may not actually be documentation on what happens, I can't tell.

    If I want to make the window draggable I can hook the hitbox test event and claim that part of my form is the title bar.


    Quote Originally Posted by Brandon View Post
    I wrote a WinAPI Library years ago that makes these things easy.. I slimmed it down a LOT to make the example more compact..

    Anyway, the solution is to actually REMOVE the styles from the window and just set the extended edges as well as thick border. To remove the styles you must do bitwise operations..

    Example:
    C++ Code:
    int flag = WS_APPWINDOW | WS_THICKFRAME | WS_BLAHBLAH | WS_MEHMEH | WS_FOOFOO;

    flag &= ~WS_APPWINDOW; //Remove WS_APPWINDOW if and only if it is set.. equivalent to "flag = flag & ~WS_APPWINDOW".
    flag &= ~WS_BLAHBLAH; //Remove WS_BLAHBLAH
    flag &= ~(WS_MEHMEH | WS_FOOFOO);  //Remove both WS_MEHMEH and WS_FOOFOO..


    Using your code..
    C++ Code:
    #define _UNICODE
    #define UNICODE

    #include <tchar.h>
    #include <Windows.h>
    #include <strsafe.h>


    LRESULT CALLBACK WndProc(
        _In_ HWND   hWnd,
        _In_ UINT   message,
        _In_ WPARAM wParam,
        _In_ LPARAM lParam
    );

    void ErrorExit(
        LPTSTR lpszFunction
    );

    HINSTANCE hInst;
    WCHAR szTitle[] = TEXT("Dummy");
    WCHAR szMenuName[] = TEXT("Dummy");
    WCHAR szWindowClass[] = TEXT("Dummy");

    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
        LPWSTR *szArgList;
        int narg;
        WNDCLASSEXW wcex;
        HWND hWnd;
        HACCEL hAccelTable;
        MSG msg;
        FILE *fConsole;

        UNREFERENCED_PARAMETER(hPrevInstance);

        szArgList = CommandLineToArgvW(GetCommandLineW(), &narg);
        if (!szArgList) {
            ErrorExit(L"CommandLineToArgvW");
        }

        // TODO: Add custom icon or use default Visual Studio icon.
        wcex.cbSize         = sizeof(WNDCLASSEX);
        wcex.style          = CS_HREDRAW | CS_VREDRAW;;
        wcex.lpfnWndProc    = WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = hInstance;
        wcex.hIcon          = LoadIcon(hInstance, IDI_APPLICATION);
        wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);

        if (narg > 1)
            wcex.hbrBackground  = CreateSolidBrush(_wtoi(szArgList[1]));
        else
            wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);

        wcex.lpszMenuName   = szMenuName;
        wcex.lpszClassName  = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, IDI_APPLICATION);
        if (!RegisterClassEx(&wcex)) {
            ErrorExit(TEXT("RegisterClassExW"));
        }

        hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);
        if (!hWnd) {
            ErrorExit(TEXT("CreateWindowExW"));
        }



        LONG style = GetWindowLong(hWnd, GWL_STYLE);
        if (!SetWindowLong(hWnd, GWL_STYLE, (style & ~WS_OVERLAPPEDWINDOW) | WS_BORDER | WS_THICKFRAME)) {
            ErrorExit(TEXT("SetWindowLong"));
        }

        style = GetWindowLong(hWnd, GWL_EXSTYLE);
        if (!SetWindowLong(hWnd, GWL_EXSTYLE, style & ~WS_EX_CLIENTEDGE)) {
            ErrorExit(TEXT("SetWindowLong"));
        }

        // Necessary per API reference for SetWindowLong. If left out,
        // there will be a persistent rendering artifact after the first
        // window move if the window has not been resized.
        if (!SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED)) {
            ErrorExit(TEXT("SetWindowPos"));
        }

        ShowWindow(hWnd, nCmdShow);
        if (!UpdateWindow(hWnd)) {
            ErrorExit(TEXT("UpdateWindow"));
        }

        hAccelTable = LoadAccelerators(hInstance, 0);
        while (GetMessage(&msg, nullptr, 0, 0)) {
            if (!TranslateAccelerator(hWnd, nullptr, &msg)) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }

        return (int)msg.wParam;
    }

    LRESULT CALLBACK
    WndProc(
        _In_ HWND   hWnd,
        _In_ UINT   message,
        _In_ WPARAM wParam,
        _In_ LPARAM lParam
    )
    {
        switch (message) {
        case WM_DESTROY: {
            PostQuitMessage(0);
            break;
        }
        default: {
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        }
        return 0;
    }

    void
    ErrorExit(
        LPTSTR lpszFunction
    )
    {
        // Retrieve the system error message for the last error code.
        LPVOID lpMsgBuf;
        LPVOID lpDisplayBuf;
        DWORD lerr = GetLastError();
        DWORD size = FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            lerr,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR)&lpMsgBuf,
            0, NULL);

        // Print the error message to the console.
        //wprintf(TEXT("%s: %s"), lpszFunction, (wcharTEXT *)lpMsgBuf);

        // Display the error message in a message box.
        lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
            (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
        StringCchPrintf((LPTSTR)lpDisplayBuf,
            LocalSize(lpDisplayBuf) / sizeof(TCHAR),
            TEXT("%s failed with error %d: %s"),
            lpszFunction, lerr, lpMsgBuf);
        MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);

        LocalFree(lpMsgBuf);
        ExitProcess(lerr);
    }
    I just tried that and I receive the same white bar at the top. The reason I'm not taking the conjunction of the existing value and the relevant flag's complement is, as far as I'm aware, I want to disable all of them; it seems like I have been doing that properly.

    I've also made the window transparent and there is still a white bar at the top. I've not yet gotten it to update properly however - the mouse and window movement will be smeared across it.

    c++ Code:
    #define _UNICODE

    #include <tchar.h>
    #include <Windows.h>
    #include <strsafe.h>

    LRESULT CALLBACK WndProc(
        _In_ HWND   hWnd,
        _In_ UINT   message,
        _In_ WPARAM wParam,
        _In_ LPARAM lParam
    );

    void ErrorExit(
        LPTSTR lpszFunction
    );

    HINSTANCE hInst;
    WCHAR szTitle[] = L"Dummy";
    WCHAR szMenuName[] = L"Dummy";
    WCHAR szWindowClass[] = L"Dummy";

    int APIENTRY
    wWinMain(
        _In_     HINSTANCE  hInstance,
        _In_opt_ HINSTANCE  hPrevInstance,
        _In_     LPWSTR     lpCmdLine,
        _In_     int        nCmdShow
    )
    {
        LPWSTR *szArgList;
        int narg;
        WNDCLASSEXW wcex;
        HWND hWnd;
        LONG lStyle;
        HACCEL hAccelTable;
        MSG msg;
        FILE *fConsole;

        UNREFERENCED_PARAMETER(hPrevInstance);

        szArgList = CommandLineToArgvW(GetCommandLineW(), &narg);
        if (!szArgList) {
            ErrorExit(L"CommandLineToArgvW");
        }

        // TODO: Add custom icon or use default Visual Studio icon.
        wcex.cbSize         = sizeof(WNDCLASSEX);
        wcex.style          = CS_HREDRAW | CS_VREDRAW;;
        wcex.lpfnWndProc    = WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = hInstance;
        wcex.hIcon          = LoadIcon(hInstance, IDI_APPLICATION);
        wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
       
        if (narg > 1)
            wcex.hbrBackground  = CreateSolidBrush(_wtoi(szArgList[1]));
        else
            wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
       
        wcex.lpszMenuName   = szMenuName;
        wcex.lpszClassName  = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, IDI_APPLICATION);
        if (!RegisterClassEx(&wcex)) {
            ErrorExit(L"RegisterClassExW");
        }

        hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);
        if (!hWnd) {
            ErrorExit(L"CreateWindowExW");
        }
       
        lStyle = GetWindowLong(hWnd, GWL_STYLE);
        if (!SetWindowLongPtr(hWnd, GWL_STYLE,
                (lStyle & ~WS_OVERLAPPEDWINDOW) | WS_BORDER | WS_THICKFRAME)) {
            ErrorExit(L"SetWindowLongPtr");
        }
       
        lStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
        if (!SetWindowLongPtr(hWnd, GWL_EXSTYLE,
                (lStyle & ~WS_EX_CLIENTEDGE) | WS_EX_TRANSPARENT | WS_EX_LAYERED)) {
            ErrorExit(L"SetWindowLongPtr");
        }
       
        // Necessary per API reference for SetWindowLong. If left out,
        // there will be a persistent rendering artifact after the first
        // window move if the window has not been resized.
        if (!SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0,
                SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER |
                SWP_FRAMECHANGED)) {
            ErrorExit(TEXT("SetWindowPos"));
        }
       
        ShowWindow(hWnd, nCmdShow);
        if (!UpdateWindow(hWnd)) {
            ErrorExit(TEXT("UpdateWindow"));
        }
       
        hAccelTable = LoadAccelerators(hInstance, 0);
        while (GetMessage(&msg, nullptr, 0, 0)) {
            if (!TranslateAccelerator(hWnd, nullptr, &msg)) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
       
        return (int)msg.wParam;
    }

    LRESULT CALLBACK
    WndProc(
        _In_ HWND   hWnd,
        _In_ UINT   message,
        _In_ WPARAM wParam,
        _In_ LPARAM lParam
    )
    {
        switch (message) {
        case WM_DESTROY: {
            PostQuitMessage(0);
            break;
        }
        default: {
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        }
        return 0;
    }

    void
    ErrorExit(
        LPTSTR lpszFunction
    )
    {
        // Retrieve the system error message for the last error code.
        LPVOID lpMsgBuf;
        LPVOID lpDisplayBuf;
        DWORD lerr = GetLastError();
        DWORD size = FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            lerr,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR)&lpMsgBuf,
            0, NULL);

        // Print the error message to the console.
        //wprintf(TEXT("%s: %s"), lpszFunction, (wcharTEXT *)lpMsgBuf);

        // Display the error message in a message box.
        /*
        lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
            (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
        StringCchPrintf((LPTSTR)lpDisplayBuf,
            LocalSize(lpDisplayBuf) / sizeof(TCHAR),
            TEXT("%s failed with error %d: %s"),
            lpszFunction, lerr, lpMsgBuf);
        MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);

        LocalFree(lpMsgBuf);
        */

        ExitProcess(lerr);
    }
    Last edited by R0b0t1; 05-10-2017 at 04:44 AM.
    The jealous temper of mankind, ever more disposed to censure than
    to praise the work of others, has constantly made the pursuit of new
    methods and systems no less perilous than the search after unknown
    lands and seas.

  11. #11
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by R0b0t1 View Post
    ...
    The code I posted worked on my comp with no white bar.. You sure you're not doing something else?


    Anyway, you can try something like Layered-Windows instead.. then use DesktopWindowManagement API to extend the client area to the bars:

    C++ Code:
    #include <windows.h>
    #include <d3d9.h>
    #include <d3dx9.h>
    #include <dwmapi.h>
    #include <iostream>


    struct VERTEX {FLOAT X, Y, Z; DWORD COLOR;};
    const unsigned int FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;

    struct VERTEX vertices[] =
    {
        {3.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0)},
        {0.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255)},
        {0.0f, 0.0f, 10.0f, D3DCOLOR_XRGB(255, 0, 0)},
        {-3.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 255)},
        {3.2f, -1.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255)},
        {3.2f, -1.0f, 11.0f, D3DCOLOR_XRGB(0, 255, 0)},
        {2.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0)},
        {-3.2f, -1.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255)},
        {-3.2f, -1.0f, 11.0f, D3DCOLOR_XRGB(0, 255, 0)},
        {-2.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0)}
    };

    short indices[] =
    {
        0, 1, 2,
        2, 1, 3,
        3, 1, 0,
        0, 2, 3,
        4, 5, 6,
        7, 8, 9,
    };


    void D3DSetRenderModes(IDirect3DDevice9* device)
    {
        device->SetRenderState(D3DRS_LIGHTING, false);
        device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
        device->SetRenderState(D3DRS_ZENABLE, true);
    }

    void D3DSetCamera(IDirect3DDevice9* device)
    {
        D3DXMATRIX view;
        D3DXVECTOR3 camera = {0.0f, 8.0f, 25.0f};
        D3DXVECTOR3 eye = {0.0f, 0.0f, 0.0f};
        D3DXVECTOR3 up = {0.0f, 1.0f, 0.0f};
        D3DXMatrixLookAtLH(&view, &camera, &eye, &up);
        device->SetTransform(D3DTS_VIEW, &view);

        D3DXMATRIX projection;
        D3DXMatrixPerspectiveFovLH(&projection, D3DXToRadian(45), 1, 1.0f, 100.0f);
        device->SetTransform(D3DTS_PROJECTION, &projection);

        static float Y = 0.0f;
        D3DXMATRIX rotation;
        D3DXMatrixRotationY(&rotation, Y += 0.01);
        device->SetTransform(D3DTS_WORLD, &rotation);
    }

    void D3DInitGraphics(IDirect3DDevice9* device, IDirect3DVertexBuffer9** vbo, IDirect3DIndexBuffer9** ibo)
    {
        device->CreateVertexBuffer(sizeof(vertices), 0, FVF, D3DPOOL_MANAGED, vbo, nullptr);
        device->CreateIndexBuffer(sizeof(indices), 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, ibo, nullptr);

        void* pData = nullptr;
        (*vbo)->Lock(0, 0, &pData, 0);
        memcpy(pData, vertices, sizeof(vertices));
        (*vbo)->Unlock();

        pData = nullptr;
        (*ibo)->Lock(0, 0, &pData, 0);
        memcpy(pData, indices, sizeof(indices));
        (*ibo)->Unlock();
    }

    void D3DDestroyGraphics(IDirect3DVertexBuffer9** vbo, IDirect3DIndexBuffer9** ibo)
    {
        if (ibo && *ibo)
        {
            (*ibo)->Release();
            *ibo = nullptr;
        }

        if (vbo && *vbo)
        {
            (*vbo)->Release();
            *vbo = nullptr;
        }
    }

    void D3DRender(IDirect3D9* d3d, IDirect3DDevice9* device,IDirect3DVertexBuffer9 *vbo, IDirect3DIndexBuffer9* ibo, HWND hwnd, D3DCOLOR bColour)
    {
        D3DSetRenderModes(device);
        D3DSetCamera(device);

        device->Clear(0, NULL, D3DCLEAR_TARGET, bColour, 1.0f, 0);
        device->Clear(0, NULL, D3DCLEAR_ZBUFFER, bColour, 1.0f, 0);
        device->BeginScene();

        device->SetFVF(FVF);
        device->SetStreamSource(0, vbo, 0, sizeof(VERTEX));
        device->SetIndices(ibo);
        device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, sizeof(vertices) / sizeof(VERTEX), 0, 6);

        device->EndScene();
        device->Present(NULL, NULL, NULL, NULL);
    }


    void InitD3D(IDirect3D9** d3d, IDirect3DDevice9** device, HWND window, int width, int height)
    {
        *d3d = Direct3DCreate9(D3D_SDK_VERSION);

        D3DPRESENT_PARAMETERS parameters;
        ZeroMemory(&parameters, sizeof(parameters));
        parameters.Windowed = true;
        parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
        parameters.hDeviceWindow = window;
        parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
        parameters.BackBufferWidth = width;
        parameters.BackBufferHeight = height;
        parameters.EnableAutoDepthStencil = TRUE;
        parameters.AutoDepthStencilFormat = D3DFMT_D16;

        (*d3d)->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &parameters, device);
    }

    void DestroyD3D(IDirect3D9** d3d, IDirect3DDevice9** device)
    {
        if(device && *device)
        {
            (*device)->Release();
            *device = nullptr;
        }

        if(d3d && *d3d)
        {
            (*d3d)->Release();
            *d3d = nullptr;
        }
    }



    void GetWindowCenter(int &centerX, int &centerY, int width, int height)
    {
        RECT rect = {0};
        GetClientRect(GetDesktopWindow(), &rect);
        centerX = (rect.right / 2) - (width / 2);
        centerY = (rect.bottom /2 ) - (height / 2);
    }

    LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch(message)
        {
            case WM_PAINT:
            {
                MARGINS margin = {-1};
                DwmExtendFrameIntoClientArea(hwnd, &margin);
            }
            break;

            case WM_KEYDOWN:
            {
                if(wParam == VK_ESCAPE)
                {
                    SendMessage(hwnd, WM_CLOSE, 0, 0);
                    return 0;
                }
            }
            break;

            case WM_DESTROY:
                PostQuitMessage(0);
                break;

            default:
                break;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
    {
        MSG msg = {0};
        int width = 500;
        int height = 500;
        D3DCOLOR bColour = D3DCOLOR_ARGB(0, 0, 0, 0);

        WNDCLASSEX wincl;
        wincl.hInstance = hInstance;
        wincl.lpszClassName = "D3DWindowClass";
        wincl.lpfnWndProc = WindowProcedure;
        wincl.style = CS_HREDRAW | CS_VREDRAW;
        wincl.cbSize = sizeof(WNDCLASSEX);
        wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wincl.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
        wincl.hCursor = LoadCursor(NULL, IDC_ARROW);
        wincl.lpszMenuName = NULL;
        wincl.cbClsExtra = 0;
        wincl.cbWndExtra = 0;
        wincl.hbrBackground = CreateSolidBrush(bColour);

        if(!RegisterClassEx(&wincl))
            return 0;

        int x = 0, y = 0;
        GetWindowCenter(x, y, width, height);
        HWND hwnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TRANSPARENT, wincl.lpszClassName, "D3DWindow", WS_POPUP, x, y, width, height, nullptr, nullptr, hInstance, nullptr);

        SetLayeredWindowAttributes(hwnd, bColour, 0, ULW_COLORKEY);
        SetLayeredWindowAttributes(hwnd, 0, 0xFF, LWA_ALPHA);
        ShowWindow(hwnd, nCmdShow);

        IDirect3D9* d3d = nullptr;
        IDirect3DDevice9* device = nullptr;
        IDirect3DVertexBuffer9 *vbo = nullptr;
        IDirect3DIndexBuffer9* ibo = nullptr;

        InitD3D(&d3d, &device, hwnd, width, height);
        D3DInitGraphics(device, &vbo, &ibo);

        while(true)
        {
            while(PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) > 0) //Use GetMessage if not using Direct-X or OpenGL.
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }

            //For D3D9.
            if(msg.message == WM_QUIT) break;

            D3DRender(d3d, device, vbo, ibo, hwnd, bColour);
        }

        D3DDestroyGraphics(&vbo, &ibo);
        DestroyD3D(&d3d, &device);
        return msg.wParam;
    }


    I used D3D9 to show that the window title stuff is gone and that a 3D model is rendering semi-transparent over top anything on your desktop..
    I am Ggzz..
    Hackintosher

  12. #12
    Join Date
    Dec 2006
    Location
    Banville
    Posts
    3,914
    Mentioned
    12 Post(s)
    Quoted
    98 Post(s)

    Default

    @Brandon, which OS are you using? On Windows 10, the code that you modified still results in the small title bar. I was able to compile your D3D example but after integrating some of the changes into the dummy window program, per the name of the function (DwmExtendFrameIntoClientArea), it looks like the API can only extend the window frame into the client area of the window. A negative value seems to be a flag value for special processing or undefined behavior.

    With my simple program the fill color is not honored and the entire window is white (add -ldwmapi):
    c++ Code:
    #define _UNICODE

    #include <tchar.h>
    #include <Windows.h>
    #include <dwmapi.h>
    #include <strsafe.h>

    LRESULT CALLBACK WndProc(
        _In_ HWND   hWnd,
        _In_ UINT   message,
        _In_ WPARAM wParam,
        _In_ LPARAM lParam
    );

    void ErrorExit(
        LPTSTR lpszFunction
    );

    HINSTANCE hInst;
    WCHAR szTitle[] = L"Dummy";
    WCHAR szMenuName[] = L"Dummy";
    WCHAR szWindowClass[] = L"Dummy";

    int APIENTRY
    wWinMain(
        _In_     HINSTANCE  hInstance,
        _In_opt_ HINSTANCE  hPrevInstance,
        _In_     LPWSTR     lpCmdLine,
        _In_     int        nCmdShow
    )
    {
        LPWSTR *szArgList;
        int narg;
        WNDCLASSEXW wcex;
        HWND hWnd;
        LONG lStyle;
        HACCEL hAccelTable;
        MSG msg;
        FILE *fConsole;

        UNREFERENCED_PARAMETER(hPrevInstance);

        szArgList = CommandLineToArgvW(GetCommandLineW(), &narg);
        if (!szArgList) {
            ErrorExit(L"CommandLineToArgvW");
        }

        // TODO: Add custom icon or use default Visual Studio icon.
        wcex.cbSize         = sizeof(WNDCLASSEX);
        wcex.style          = CS_HREDRAW | CS_VREDRAW;;
        wcex.lpfnWndProc    = WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = hInstance;
        wcex.hIcon          = LoadIcon(hInstance, IDI_APPLICATION);
        wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
       
        if (narg > 1)
            wcex.hbrBackground  = CreateSolidBrush(_wtoi(szArgList[1]));
        else
            wcex.hbrBackground  = (HBRUSH)GetStockObject(BLACK_BRUSH); //(HBRUSH)(COLOR_WINDOW + 1);
       
        wcex.lpszMenuName   = szMenuName;
        wcex.lpszClassName  = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, IDI_APPLICATION);
        if (!RegisterClassEx(&wcex)) {
            ErrorExit(L"RegisterClassExW");
        }

        hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);
        if (!hWnd) {
            ErrorExit(L"CreateWindowExW");
        }
       
        lStyle = GetWindowLong(hWnd, GWL_STYLE);
        if (!SetWindowLongPtr(hWnd, GWL_STYLE,
                WS_BORDER | WS_THICKFRAME)) {
            ErrorExit(L"SetWindowLongPtr");
        }
       
        //lStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
        //if (!SetWindowLongPtr(hWnd, GWL_EXSTYLE,
        //      (lStyle & ~WS_EX_CLIENTEDGE) | WS_EX_TRANSPARENT | WS_EX_LAYERED)) {
        //  ErrorExit(L"SetWindowLongPtr");
        //}
       
        // Necessary per API reference for SetWindowLong. If left out,
        // there will be a persistent rendering artifact after the first
        // window move if the window has not been resized.
        if (!SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0,
                SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER |
                SWP_FRAMECHANGED)) {
            ErrorExit(TEXT("SetWindowPos"));
        }
       
        ShowWindow(hWnd, nCmdShow);
        if (!UpdateWindow(hWnd)) {
            ErrorExit(TEXT("UpdateWindow"));
        }
       
        hAccelTable = LoadAccelerators(hInstance, 0);
        while (GetMessage(&msg, nullptr, 0, 0)) {
            if (!TranslateAccelerator(hWnd, nullptr, &msg)) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
       
        return (int)msg.wParam;
    }

    LRESULT CALLBACK
    WndProc(
        _In_ HWND   hWnd,
        _In_ UINT   message,
        _In_ WPARAM wParam,
        _In_ LPARAM lParam
    )
    {
        switch (message) {
        case WM_DESTROY: {
            PostQuitMessage(0);
            break;
        }
        case WM_PAINT: {
            MARGINS margin = {0, 0, -25, 0};
            if (DwmExtendFrameIntoClientArea(hWnd, &margin)) {
                ErrorExit(L"DwmExtendFrameIntoClientArea");
            }
            break;
        }
        case WM_NCHITTEST: {
            LRESULT result = DefWindowProc(hWnd, message, wParam, lParam);
           
            if (result == HTCLIENT)
                return HTCAPTION;
            else
                return result;
        }
        default: {
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        }
        return 0;
    }

    void
    ErrorExit(
        LPTSTR lpszFunction
    )
    {
        // Retrieve the system error message for the last error code.
        LPVOID lpMsgBuf;
        LPVOID lpDisplayBuf;
        DWORD lerr = GetLastError();
        DWORD size = FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            lerr,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR)&lpMsgBuf,
            0, NULL);

        // Print the error message to the console.
        wprintf(TEXT("%s: %s"), lpszFunction, (wchar_t *)lpMsgBuf);
        ExitProcess(lerr);
    }

    Per examples for other usecases, it seems like a black fill and a negative margin will result in transparency, which is not what I am looking for. Is there a way to disable transparency? I tried to refer to the DWM API reference, but the functions seem very limited. It seems like they were created to support things like Office and Internet Explorer toolbars.
    The jealous temper of mankind, ever more disposed to censure than
    to praise the work of others, has constantly made the pursuit of new
    methods and systems no less perilous than the search after unknown
    lands and seas.

  13. #13
    Join Date
    May 2007
    Location
    England/Liverpool
    Posts
    1,004
    Mentioned
    9 Post(s)
    Quoted
    106 Post(s)

    Default

    I had a problem like this tho it was when i wrote a CrossHair for a couple online games i played that never had one so i wrote my own in delphi.
    This will display over any game running in fullscreen windowed without a border transparent and will not receive mouse events.
    but i think what you need to do is set your border style to bsNone have it transparent and paint what is needed after.

    this is from my CrossHair It App i made.
    Simba Code:
    unit Main;

    interface

    uses
    Windows, ExtCtrls, Classes, Controls, Forms, Math,  Sysutils;

    type
      TForm1 = class(TForm)
        Timer1: TTimer;
        Image1: TImage;
        Controls: TTimer;
        procedure FormCreate(Sender: TObject);
        procedure Timer1Timer(Sender: TObject);
        procedure ControlsTimer(Sender: TObject);
      private
        { Private declarations }
      public
        CrosshairOffset:integer;
        { Public declarations }
      end;

    var
      Form1: TForm1;
      OffSetx,  OffSety : Integer;
    implementation

    uses Options;

    {$R *.dfm}

    procedure TForm1.FormCreate(Sender: TObject);
    begin

        form1.BorderStyle :=  bsNone;
        Form1.FormStyle :=  fsStayOnTop
        SetWindowLong(form1.Handle, GWL_EXSTYLE,
        GetWindowLong(form1.Handle, GWL_EXSTYLE) or WS_EX_TRANSPARENT );
        SetLayeredWindowAttributes(form1.Handle, 0, 255, LWA_COLORKEY);
        form1.Width :=  image1.Width;
        form1.Height  :=  image1.Height;
    end;


    procedure TForm1.Timer1Timer(Sender: TObject);
    begin
        form1.Left:= screen.Width div 2 - Round(image1.Width / 2) + OffSetx;
        form1.Top:= Screen.Height div 2 - Round(image1.Height / 2)  + OffSety;
    end;

    //used for manual adjusting crosshair offset when centred not required
    procedure TForm1.ControlsTimer(Sender: TObject);
    begin
      if GetAsyncKeyState(vk_f12) <> 0 then  //Will make the crosshair vissible / invisible
      begin
        if Form1.Visible  = false then
        begin
          Form1.Visible  :=  True;
        end else
          form1.Visible :=  False;
      end;
      if (GetAsyncKeyState(VK_CONTROL) <> 0)  and (GetAsyncKeyState(VK_Left)  <>  0)  then
      begin
        OffSetx :=  OffSetx - 1;
      end;
      if (GetAsyncKeyState(VK_CONTROL) <> 0)  and (GetAsyncKeyState(VK_Right)  <>  0)  then
      begin
        OffSetx :=  OffSetx + 1;
      end;
      if (GetAsyncKeyState(VK_CONTROL) <> 0)  and (GetAsyncKeyState(VK_Up)  <>  0)  then
      begin
        OffSety :=  OffSety - 1;
      end;
      if (GetAsyncKeyState(VK_CONTROL) <> 0)  and (GetAsyncKeyState(VK_Down)  <>  0)  then
      begin
        OffSety :=  OffSety + 1;
      end;

    end;

    end.
    Previously Known or not Known as CRU1Z1N.
    If you want to succeed you should strike out on new paths, rather than travel the worn paths of accepted success.(John D. Rockefeller)

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •