0

I'm creating a basic notepad program, and when the user clicks close, I want it to ask the user if they want to save the current document opened. I'm using a tabbed interface, and trying to retrieve the filename ( text on tab ) so I have a MessageBox that says "Would you like to save: untitled.txt" or similar. I'm having trouble getting the file name. This is what I currently have:

case ID_FILE_CLOSE:  // When the close button is clicked
  {
    HWND hEdit, hTabs;
    hTabs = GetDlgItem( hwnd, IDC_MAIN_TAB );
    int curTab = TabCtrl_GetCurSel( hTabs );

    TCITEM curtitem;
    TabCtrl_GetItem( hTabs, curTab, &curtitem );

    // Check for file name
    MessageBox( hwnd, curtitem.pszText, "Test", MB_OK );
  }
  break;

This is the error I keep getting in a popup box with Break, Continue, Ignore buttons:

Unhandled exception at 0x7597d298 in notepadpremium.exe: 0xC0000005: Access violation reading location 0xcccccccc.

I'm using MS Visual C++ Express 2010.

I also have a listbox with the filenames that also show the extension ( almost like notepad++ document switcher ) and tried LB_GETITEMDATA through a message, but that always returned blank. I think that was because I use LB_ADDSTRING to add it to the listbox. ( the listbox and tabs are interconnected, when you click on a file in the listbox, it changes to the corresponding tab ). Why isnt my code working the way it should?

IInspectable
  • 46,945
  • 8
  • 85
  • 181
Vince
  • 2,596
  • 11
  • 43
  • 76

1 Answers1

3

Read the documentation:

pitem Type: LPTCITEM

Pointer to a TCITEM structure that specifies the information to retrieve and receives information about the tab. When the message is sent, the mask member specifies which attributes to return. If the mask member specifies the TCIF_TEXT value, the pszText member must contain the address of the buffer that receives the item text, and the cchTextMax member must specify the size of the buffer.

You are not initializing the TCITEM at all. You need to tell TabCtrl_GetItem() what data to retrieve, and more importantly what buffer you provide to receive that data into. You are not doing any of that, you are passing random data to TabCtrl_GetItem(), which is why it crashes.

Try this instead:

case ID_FILE_CLOSE:  // When the close button is clicked
  {
    HWND hTabs = GetDlgItem( hwnd, IDC_MAIN_TAB );

    int curTab = TabCtrl_GetCurSel( hTabs );
    TCHAR szFileName[MAX_PATH+1] = {0};

    TCITEM curtitem = {0};
    curitem.mask = TCIF_TEXT;
    curitem.pszText = szFileName;
    curitem.cchTextMax = MAX_PATH;

    if (TabCtrl_GetItem( hTabs, curTab, &curtitem ))
    {
      // also from the documentation:
      //
      // "the control may change the pszText member of the structure
      // to point to the new text instead of filling the buffer with
      // the requested text. The control may set the pszText member
      // to NULL to indicate that no text is associated with the item."
      //
      // which means you cannot rely on the szFileName[] buffer actually
      // containing the filename, you have to use whatever buffer the
      // TCITEM is actually pointing at, which may or may not be the
      // szFileName buffer...

      MessageBox( hwnd, curitem.pszText, TEXT("Test"), MB_OK );
    }
  }
  break;

As for your ListBox issue, you said you are using LB_ADDSTRING to add strings to the ListBox, but are using LB_GETITEMDATA to retrieve them. That is wrong. You need to use LB_GETTEXTLEN and LB_GETTEXT instead. LB_GETITEMDATA is used to retrieve user-defined data that was added to the ListBox using LB_SETITEMDATA.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770