1

I'm trying to add some application controls into my Windows API code (Note: I am using Visual Studio) I am experiencing a problem where I try to add in a CreateWindowW() function that generates text and a field ("static" and "edit") and a menu at the same time. The menu works fine on its own ("Calculations"):

Without the CreateWindowW() function

However, adding the CreateWindow() function "erases" the menu entirely but yields the CreateWindowW() outputs (also flickers a bit):

With the CreateWindowW() function

The code I have right now is this (the menu function and the CreateWindowW() functions are at the bottom):

#define MAX_LOADSTRING 100
#define FILE_MENU_DESTROY 1
#define FILE_MENU_ABOUT 2

// Global Variables:
HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
//INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

//Custom Application Function Forwrd Declarations
void WinControls(HWND);
void WinMenu(HWND);
HMENU hMenu;

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_RANKTOOLADVANCED, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance); //Generates an instance of a window class

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }
    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_RANKTOOLADVANCED));

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)//Class properties of the window
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc; //assigns a window to the instance of the class
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance; //creates an instance
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_RANKTOOLADVANCED));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW); //defines a type of cursor (arrow, help, cross, etc.)
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1); 
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_RANKTOOLADVANCED);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{//initializes instance of window class (invocation)
   hInst = hInstance; // Store instance handle in our global variable

   HWND hWnd = CreateWindowW(szWindowClass, L"test", WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, 900, 600, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
    {
        int wmId = LOWORD(wParam);
        // Parse the menu selections:
        switch (wmId)
        {/*
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        case FILE_MENU_NEW:
        {
            MessageBox(hWnd, L"task failed successfully", L"you done goofed", MB_OK | MB_ICONEXCLAMATION);
            break;
        }*/
        case FILE_MENU_DESTROY:
        {
            DestroyWindow(hWnd);
            break;
        }
        case FILE_MENU_ABOUT:
        {
            MessageBox(hWnd, L"about", L"About", MB_OK);
            break;
        }
        break;
        }
    }
    case WM_CREATE:
        {
            WinControls(hWnd);
            WinMenu(hWnd);
            break;
        }/*
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code that uses hdc here...
            TextOut(hdc, 10, 10, rekt, _tcslen(rekt));
            TextOut(hdc, 10, 40, reverse, _tcslen(reverse));
            EndPaint(hWnd, &ps);
            break;
        }*/
    case WM_DESTROY:
    {
        PostQuitMessage(0);
        break;
    }
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

void WinMenu(HWND hWnd) {

    hMenu = CreateMenu();
    HMENU hFileMenu = CreateMenu();
    HMENU hSubMenu = CreateMenu();
    HMENU hSubMenu2 = CreateMenu();

    //XP Calculations
    AppendMenuW(hSubMenu, MF_STRING, NULL, L"Rank -> XP");
    AppendMenuW(hSubMenu, MF_STRING, NULL, L"XP -> Rank");

    //Credit Calculations
    AppendMenuW(hSubMenu2, MF_STRING, NULL, L"Rank -> Cred");
    AppendMenuW(hSubMenu2, MF_STRING, NULL, L"Cred -> Rank");



    AppendMenuW(hFileMenu, MF_POPUP, (UINT_PTR)hSubMenu, L"Points"); //option that popups submenu of hSubMenu
    AppendMenuW(hFileMenu, MF_POPUP, (UINT_PTR)hSubMenu2, L"Credits"); //option that popups submenu of hSubMenu
    AppendMenuW(hFileMenu, MF_SEPARATOR, NULL, NULL); // separator
    AppendMenuW(hFileMenu, MF_STRING, FILE_MENU_ABOUT, L"About");
    AppendMenuW(hFileMenu, MF_STRING, FILE_MENU_DESTROY, L"Exit"); // option 

    AppendMenuW(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, L"Calculations"); //popups up submenu of hFileMenu

    SetMenu(hWnd, hMenu);
}

void WinControls(HWND hWnd) {
    CreateWindowW(L"Static", L"Enter text here: ", WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER, 400, 100, 100, 50, hWnd, NULL, NULL, NULL);
    CreateWindowW(L"Edit", L"...", WS_VISIBLE | WS_CHILD, 400, 155, 100, 50, hWnd, NULL, NULL, NULL);
}

Please do note that the setup is the Visual Studio basic setup for the program. Any help is appreciated!

Peter
  • 373
  • 3
  • 10
  • 4
    Are you sure the problem is with the CreateWindow and not the SetMenu? The submenus should be popup menus, not menu bar menus. – Raymond Chen Mar 29 '20 at 05:20
  • And is there a reason to create this menu in code rather than as a resource assigned to the window class? – SoronelHaetir Mar 29 '20 at 06:22
  • @Raymond Chen I'll try fiddling around with the SetMenu, then see where I can go from there. Also, may you please elaborate on "popup" menus for the submenus? – Peter Mar 29 '20 at 15:09
  • @SoronalHaetir I don't know how to use the .rc file as I am quite a noob at this – Peter Mar 29 '20 at 15:10
  • Ok so I have fiddled around with the code, and it appears that the SetMenu() is conflicting with the CreateWindowW() function. Commenting out the SetMenu() creates the default menu and creates the desired static and edit elements I want, but the custom menu does not allow. This is quite interesting... – Peter Mar 29 '20 at 16:40
  • 1
    You don't have a `break;` at the end of the `case WM_COMMAND:` so when a command comes in from the edit control, you just fall through to the `case WM_CREATE`. – Raymond Chen Mar 30 '20 at 13:25
  • @RaymondChen Thanks for finding that! I've fixed it now – Peter Mar 31 '20 at 02:19

1 Answers1

0

I have done some debugging and figured out it was that the CreateWindowW() I used for the static and edit controls was conflicting with the definition of the window properties.

Since the window was defined by WNDCLASSEXW wcex, I just had to change the CreateWindowW() with CreateWindowExW().

Only new problem is that the static control (and the others) works but not the edit control, which kills the menu.

Peter
  • 373
  • 3
  • 10
  • CreateWindow is same as CreatewindowEx with zero extended styles. And what you mean by ''definition of the window properties"? – user2120666 Mar 29 '20 at 18:15
  • In a perfect world, I'd like to think that I know a lot, but I'm still a novice at win32 API, so I really don't know how it works, but I know that I can use it (somehow). – Peter Mar 29 '20 at 20:57