Example for LVM_SUBITEMHITTEST - c++

Could some kind person show me an example of how to use LVM_SUBITEMHITTEST?
I've tried the following code, but both the return value of SendMessage() and the relevant members of myinfo are always -1, no matter where in my ListView I click.
case NM_RCLICK:
{
NMITEMACTIVATE itemClicked = *(NMITEMACTIVATE*)lParam;
LVHITTESTINFO myinfo;
memset(&myinfo, 0, sizeof(myinfo));
POINT cursorPos;
GetCursorPos(&cursorPos);
myinfo.pt = cursorPos;
// I find that itemNumber as well as myinfo->iItem and myinfo->iSubItem
// are always set to -1 by the following line
int itemNumber = SendMessage(myListviewHwnd, LVM_SUBITEMHITTEST, 0,(LPARAM)&myinfo);
}
I based my code off of the following MSDN articles:
NM_RCLICK (list view) notification code
LVM_SUBITEMHITTEST message
But they don't list any examples, so I'm worried I'm doing something stupid :(

Update: I was doing something stupid. The LVM_SUBITEMHITTEST function wants client coordinates, not screen coordinates. Here's a working example:
case NM_RCLICK:
{
NMITEMACTIVATE itemClicked = *(NMITEMACTIVATE*)lParam;
LVHITTESTINFO myinfo;
memset(&myinfo, 0, sizeof(myinfo));
POINT cursorPos;
GetCursorPos(&cursorPos);
ScreenToClient(myListviewHwnd, &cursorPos);
myinfo.pt = cursorPos;
int itemNumber = SendMessage(myListviewHwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&myinfo);
}

In my case, I solved the same issue like this:
LVHITTESTINFO lvHit;
memset(&lvHit,0, sizeof(LVHITTESTINFO));
lvHit.pt = pNMItemActivate->ptAction;
m_list.SubItemHitTest(&lvHit); // !! Use SubItemHitTest, not HitTest
iItem = lvHit.iItem;
iSubItem = lvHit.iSubItem;

Related

Specific filepath to store Screen Record using CGDisplayStream in OSX

I have been working on a c++ command line tool to record screen. After some searching I have come up with this following code. Looks like screen is being recorded when I compile and run the code. I am looking for functions where I can provide the specific filepath where the screen record is to be stored. Also I would like to append the timestamp along with filename. If anybody has better approach or method to this problem please suggest here. Any leads are appreciated. Thanks
#include <ApplicationServices/ApplicationServices.h>
int main(int argc, const char * argv[]) {
// insert code here...
CGRect mainMonitor = CGDisplayBounds(CGMainDisplayID());
CGFloat monitorHeight = CGRectGetHeight(mainMonitor);
CGFloat monitorWidth = CGRectGetWidth(mainMonitor);
const void *keys[1] = { kCGDisplayStreamSourceRect };
const void *values[1] = { CGRectCreateDictionaryRepresentation(CGRectMake(0, 0, 100, 100)) };
CFDictionaryRef properties = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CGDisplayStreamRef stream = CGDisplayStreamCreate(CGMainDisplayID(), monitorWidth, monitorHeight, '420f' , properties, ^(CGDisplayStreamFrameStatus status, uint64_t displayTime, IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef){});
CGDirectDisplayID displayID = CGMainDisplayID();
CGImageRef image_create = CGDisplayCreateImage(displayID);
CFRunLoopSourceRef runLoop = CGDisplayStreamGetRunLoopSource(stream);
// CFRunLoopAddSource(<#CFRunLoopRef rl#>, runLoop, <#CFRunLoopMode mode#>);
CGError err = CGDisplayStreamStart(stream);
if (err == CGDisplayNoErr) {
std::cout<<"WORKING"<<std::endl;
sleep(5);
} else {
std::cout<<"Error: "<<err<<std::endl;
}
//std::cout << "Hello, World!\n";
return 0;
}
You should do that in the callback which you provide in CGDisplayStreamCreate. You can access the pixels via IOSurfaceGetBaseAddress (see other IOSurface functions). If you don't want to do the pixel twiddling yourself, you could create a CVPixelBuffer with CVPixelBufferCreateWithBytes from the IOSurface and then create a CIImage with [CIImage imageWithCVImageBuffer] and save that to file as seen here.

Unable to pass the string variable to Sprite in cocos2dx

I'm having problem with the strings in cocos2dx & C++. I want to pass the variable background to Sprite::create(background) however, I get an error. If it was in java the following code will work, but since I'm not used to C++ it may be different. Plus, if it was a int how will I pass it ? How will I be able to solve this? Some tips or samples will be great! I will love to hear from you!
void GameLayer::initBackground()
{
UserDefault *_userDef = UserDefault::getInstance();
//int型
auto _int =_userDef->getIntegerForKey("back");
auto string background = "Background1.png";
if (_int == 0) {
background = "Background2.png";
}
auto bgForCharacter = Sprite::create(background);
bgForCharacter->setAnchorPoint(Point(0, 1));
bgForCharacter->setPosition(Point(0, WINSIZE.height));
addChild(bgForCharacter, ZOrder::BgForCharacter);
auto bgForPuzzle = Sprite::create("Background2.png");
bgForPuzzle->setAnchorPoint(Point::ZERO);
bgForPuzzle->setPosition(Point::ZERO);
addChild(bgForPuzzle, ZOrder::BgForPuzzle);
}
auto userDefault=UserDefault::getInstance();
int value=userDefault->getIntegerForKey("back"); //find value for back if exist then it return that value else return 0
auto sprite = Sprite::create(value==0?"Background2.png":"Background1.png");
sprite->setPosition(100, 100);
this->addChild(sprite, 0);
When you want to change your background just put any value rather than 0
UserDefault::getInstance()->setIntegerForKey("back", 1);

Win32 ListView - handle invalid after LVM_INSERTITEM

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.

GetMenuItemInfo does not set fType with MIIM_TYPE

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!

Windows API Combobox data not being inserted

I'm trying to assign an int to each item in a ComboBox.
Here's my code:
int itemIndex = ComboBox_InsertString(hComboBox, -1, strData);
if (itemIndex > -1)
{
// idataIndex is always 0
// and ComboBox_GetItemData() always returns 0 regardless of what intData is
int idataIndex = ComboBox_InsertItemData(hComboBox, itemIndex, intData);
}
Am I doing something wrong? This seems pretty straightforward.
EDIT:
Figured it out, ComboBox_InsertItemData sends CB_INSERTSTRING instead of CB_SETITEMDATA. I needed to send CB_SETITEMDATA to set the item data.
Have you tried to use ComboBox_SetItemData instead? This macro sends the CB_SETITEMDATA