I have a problem a window handle (window class = WC_LISTVIEW) after calling
SendMessage(hListView_, LVM_INSERTITEM , 0, (LPARAM)&lvItem);
where
hListView_
is a handle to a list view window and
lvItem
is an LVITEM structure. The following code
std::cout << "Last error: " << GetLastError() << std::endl;
SendMessage(hListView_, LVM_INSERTITEM , 0, (LPARAM)&lvItem);
std::cout << "Last error: " << GetLastError() << std::endl;
prints
Last error: 0
Last error: 6
According to Win32 System Error Codes code 6 means ERROR_INVALID_HANDLE.
I create the LVITEM structure as follows:
// define a char-buffer
char szBuffer[256];
szBuffer[0] = '\0';
// create new list view item
LVITEM lvItem;
lvItem.cchTextMax = 256;
lvItem.mask = LVIF_TEXT;
lvItem.iItem = 0;
lvItem.stateMask = 0;
lvItem.state = 0;
lvItem.iSubItem = 0;
snprintf(szBuffer, 256, "%s", myString.c_str());
lvItem.pszText = szBuffer;
This code is called from the same thread which created the window (list view).
Also note that I have
lvItem.iSubItem = 0;
which is required according to LVM_INSERTITEM. The list view is empty prior to this call. Moreover, I can actually see the value being inserted in the list view (i.e. I can see the item in the list view in the GUI).
However, when I try to use the window handle after this the application crashes (no exception, just crashes).
Greatful for any hints on what might cause this.
Thank you.
Thank you David Heffernan for your help. I did at last find the problem, which was (as you suggested) in a different place in the code.
I had missed the following line (in a different function which I call prior to the code I posted above)
lvItem.pszText = szBuffer;
where
char szBuffer[256]; // char-buffer
when doing the follwing call
SendMessage(hListView_, LVM_GETITEMTEXT, (WPARAM) i, (LPARAM) &lvItem);
Thanks a lot for your help!
Edit: If I had done
lvItem.pszText = myString.c_str();
rather than the char-buffer this would probably not have happened, so thanks for that hint!
There's no reason for you to call GetLastError. The documentation for LVM_INSERTITEM doesn't say that you should do so. All it says is that SendMessage returns the index of the new item on success, and -1 on failure. So, check for errors by inspecting the value returned by SendMessage.
The other problem is that you are not initialising all the fields of LVITEM. That's always a mistake. You can use an initialising declaration like this:
LVITEM lvItem = { 0 };
There's no real need for a separate buffer for the text. You can do it all like this:
LVITEM lvItem = { 0 };
lvItem.mask = LVIF_TEXT;
lvItem.cchTextMax = myString.length() + 1;
lvItem.pszText = myString.c_str();
int indexOfNewItem = SendMessage(hListView_, LVM_INSERTITEM, 0, (LPARAM)&lvItem);
if (indexOfNewItem == -1)
// deal with failure
It's quite possible that your error lies elsewhere in fact. I don't see any particular reason for that SendMessage call to lead to an application crash. At least now you know how to check for errors when sending LVM_INSERTITEM. If that does not result in an error then the evidence would be that the crash is caused by some other code and you have mistakenly identified this code because you erroneously called GetLastError when its value was meaningless.
Related
If I want to read a value from a certain item and sub-item in a list-view I do the following:
const int MAX_SIZE = 256;
char szBuffer[MAX_SIZE];
LVITEM lvItem = {0};
lvItem.iItem = rowIndex;
lvItem.iSubItem = subItemIndex;
lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
lvItem.cchTextMax = MAX_SIZE;
lvItem.pszText = szBuffer;
// Get item
SendMessage(hListView, LVM_GETITEM, 0, (LPARAM)&lvItem);
// Print value, which one always guaranteed to work?
std::cout << lvItem.pszText << std::endl;
std::cout << lvItem.szBuffer << std::endl;
Now, reading the MSDN Documentation on LVM_GETITEM we see that it says
Applications should not assume that the text will necessarily be placed in the specified buffer. The control may instead change the pszText member of the structure to point to the new text, rather than place it in the buffer.
How do we know when it is safe to use our buffer (szBuffer in this example) rather than using
lvItem.pszText
directly?
Maybe we always have to do (or similar):
if(lvItem.pszText != szBuffer)
snprintf(szBuffer, MAX_SIZE, "%s", lvItem.pszText);
to copy the value from the pszText of the LVITEM structure into
our buffer (after we have sent the LVM_GETITEM message of course).
I have been working with winapi just a little bit, making a project with owner draw on menus. When I called GetMenuItemInfo, it sets the text of the menu item, but not the fType UINT variable flags.
Currently I have declared:
MenuItem->fMask = MIIM_TYPE
And MSDN says:
MIIM_TYPE Retrieves or sets the fType and dwTypeData members.
I don't know If I got confused with the MIIM_TYPE flag.
Here is my code:
void SetOwnerDrawMenu(HMENU * menu)
{
MENUIF * menu_item_information;
HMENU sub_menu_ocational;
UINT uId_menuitem;
int nMenuCountItems = GetMenuItemCount(*menu);
MENUITEMINFO * MenuItem = (MENUITEMINFO*)malloc(sizeof(MENUITEMINFO));
for(int i=0;i<nMenuCountItems;i++)
{
menu_item_information = (MENUIF*)malloc(sizeof(MENUIF));
menu_item_information->isSeparator=false;
menu_item_information->max_width=0;
sub_menu_ocational = 0;
uId_menuitem = GetMenuItemID(*menu,i);
memset(&MenuItem,0,sizeof(MenuItem));
MenuItem = (MENUITEMINFO*)malloc(sizeof(MENUITEMINFO));
MenuItem->cbSize = sizeof(MenuItem);
MenuItem->fMask = MIIM_TYPE;
MenuItem->cch = MAX_ODM_CCH;
MenuItem->dwTypeData = menu_item_information->szItemText;
GetMenuItemInfo(*menu,uId_menuitem,FALSE,MenuItem);
UINT final_flags = MF_BYPOSITION | MF_OWNERDRAW;
if( ( MFT_SEPARATOR & MenuItem->fType ) == MFT_SEPARATOR )
{
final_flags |= MF_SEPARATOR;
menu_item_information->isSeparator = true;
}
else
{
// Not important stuff
}
sub_menu_ocational = GetSubMenu(*menu,i);
if(sub_menu_ocational!=NULL)
{
ModifyMenu(*menu,i,final_flags,0,(LPCTSTR)menu_item_information);
// We got a submenu, repeat this operation
SetOwnerDrawMenu(&sub_menu_ocational);
}
else
{
ModifyMenu(*menu,i,final_flags,0,(LPCTSTR)menu_item_information);
}
}
}
I am inserting the menus with the InsertMenu function:
InsertMenu(tid_cmenu,0,MF_BYPOSITION | MF_SEPARATOR,0,NULL);
InsertMenu(tid_cmenu,0, MF_BYPOSITION | MF_STRING, TID_EXIT, "Exit");
Exactly, why the GetMenuItemInfo is not retriving the fType?
If you were checking the return code from GetMenuItemInfo you would see that it is failing. Your error is in this line:
MenuItem->cbSize = sizeof(MenuItem);
The MENUITEMINFO::cbSize member is supposed to be set to the size of a MENUITEMINFO structure, but you are setting it to the size of a MENUITEMINFO* pointer (i.e. 4 or 8 bytes, depending on the platform).
Change your code to:
MenuItem->cbSize = sizeof(MENUITEMINFO);
Also, your code is allocating MenuItem outside the loop, as well as once per-iteration inside the loop, so you are leaking memory.
Ok. The problem is not syntax or memory size errors.
It is more like 'logic' error and a silly mistake.
The ModifyMenu was changing all the menu items and
setting the fType of each one to NULL or setting the MF_SEPARATOR to all of the items.
That happened because the fourth argument of the ModifyMenu should be the ID of the menu item, I was declaring it as 0.
I changed that argument to the real ID of the menu Item using the GetMenuItemID return value inside the uId_menuitem variable and passing it to the fourth argument of ModifyMenu. That fixed the problem.
Thanks!
I am attempting to set the Display Mode of my Monitor using WinAPI C++ functions.
My Problem: Calling ChangeDisplaySettingsEx() always returns DISP_CHANGE_BADPARAM. What am I doing wrong?
I think it may be my devMode.dmDriverExtra value thats causing the error. I've read MSDN and the explaination of devMode.dmDriverExtra is confusing. What is it and how do I find out the Monitors' dmDriverExtra?
Whats causing my code below to always return DISP_CHANGE_BADPARAM?
DEVMODE devMode;
POINTL p = {0,0};
_tcscpy(devMode.dmDeviceName, _T("\\Device\\00000072"));
devMode.dmSpecVersion = DM_SPECVERSION;
devMode.dmDriverVersion = 1; // How do I determine the driver version?
devMode.dmSize = sizeof(DEVMODE);
devMode.dmDriverExtra = 0x5c0000; //
devMode.dmFields = DM_POSITION;
devMode.dmPosition = p;
LONG res = ChangeDisplaySettingsEx(_T("\\Device\\00000072"), &devMode, mainHwnd, 0, NULL);
_tprintf(_T("%s: %d\n\n\n"), _T("\\Device\\00000072"), res);
// The above printf always prints out "\Device\00000072: -5" (DISP_CHANGE_BADPARAM=-5)
The hwnd parameter is documented to be reserved and must be NULL. Additionally dmDriverExtra is a 16 bit value, so 0x5c0000 doesn't fit.
I am filling a combobox:
while((pHPSet = pHPTable->GetNext()) != NULL)
{
CString str = pHPSet->GetName();
// I am normally using str but to proove that this is
// not the problem I am using "a"
m_comboBaseHP.AddString(_T("a"));
}
Now I am trying to read the combobox:
if(m_comboBaseHP.GetCount() > 0)
{
CString csHPName = _T("");
m_comboBaseHP.GetLBText(0, csHPName);
// This is the ms way but ReleaseBuffer causes a crash
//CString str = _T("");
//int n = m_comboBaseHP.GetLBTextLen( 0 );
//m_comboBaseHP.GetLBText( 0, str.GetBuffer(n) );
//str.ReleaseBuffer();
// Do whatever with csHPName
}
The problem is that csHPName shows in the Debugger some Chinese signs. I am assuming this is memory garbage. This happens in the same Method. This happens pre draw. Post draw the same issue. This happens in Debug and Release. I don't understand how this can happen since I am not actually working with pointers.
Apparently it is necessary to set the property Has Strings of the combobox to True.
I am fully aware if i try to get buffer of another app listview items that i need to solve memory space boundary so What i am doing is hooking which returns well, no error, success then
enter code here
LVITEM lvi;
lvi.cchTextMax = 552;
lvi.mask = LVIF_TEXT;
_tfreopen(path,_T("w"),stdout);
for (int nItem = 0; nItem < nMaxItems; nItem++) {
// Get the name and position of a ListView item.
lvi.iSubItem = 0;
lvi.iItem = nItem;
lvi.pszText = szName;
ListView_GetItem(hWndLV, &lvi);
wprintf(L"%s, ", szName);
wprintf(L"%s, ", lvi.pszText);
for ( int subitem = 0; subitem < columns; subitem++)
{
lvi.iSubItem = subitem;
lvi.iItem = nItem;
lvi.pszText = szName;
ListView_GetItem(hWndLV, &lvi);
wprintf(L"%s, ", szName);
wprintf(L"%s, ", lvi.pszText);
}
wprintf(L"%s", "\n");
}
wprintf(L"%s", GetLastError());
fclose (stdout);
No error with getlasterror and this works perfect on any other listview i tried before except this app, is it possible to still get item text somehow ?
Maybe it is an owner-drawn listview (LVS_OWNERDRAWFIXED)? If this is the case it will not be possible to get the text without private knowledge of the app that owns it.
You don't need to use hooking to get across the process boundary. You can use WriteProcessMemory/ReadProcessMemory as described in the following Code Project article: http://www.codeproject.com/KB/threads/int64_memsteal.aspx
What you have to watch out for is crossing a 32/64 bit boundary. I know of now way to achieve that.