I am using the LPARAM
(essentially a long
, unless we're on a 64-bit system in which case it is a long long
) member of an LVITEM
(called lParam
) to store a pointer to the object that coincides with that entry in the ListView
.
When I want to edit that item, I want to cast that LPARAM
to a MyClass*
, which works fine so long as the lParam
is correctly set to be equal to a MyClass*
in the first place, but I'd like to do some kind of checking to make sure it is, in fact, a MyClass
that this number is pointing to.
Currently I have this:
LVITEM lv;
// lv is filled in by LVM_GETITEM
classPtr = static_cast<MyClass*>((void*)lv.lParam);
if ( !classPtr )
return false;
Now, I'm not exactly clear: does static_cast
return NULL
if the argument is not a valid pointer? I assume not, since that's what dynamic_cast
is for, but I'm not entirely certain. And, if I am correct in this assumption, is there any way to check that classPtr
is valid before I attempt to access its members and cause a crash...
static_cast<>
performs no runtime checking of types, so what you have won't work, at least not the way you think it does. All static_cast<>
does is pointer arithmetic based on information known at compile time.
dynamic_cast<>
might work, but it requires that the class has at least one virtual function (for RTTI) and it'll surely fail badly if LPARAM
isn't even a pointer to something that's a class type.
There is no general way to determine, given an arbitrary pointer or integral value like an LPARAM
, that it actually points to an instance of MyClass
.
What I would do in your specific situation is to wrap the list view in its own class and expose methods that works with MyClass
only. Possibly like this:
class MyListView
{
public:
MyListView() { /* create the list view HWND */ }
~MyListView() { /* destroy the list view HWND */ }
void Add(MyClass* listItem) // Only way to add items to list view
{
// Add to list view
}
MyClass* Get() const
{
LVITEM lv;
// lv is filled in by LVM_GETITEM
// Assume that this will work, since the only way to add
// list view items is through Add(), and Add() only accepts
// an instance of MyClass. Therefore the list view will only
// have pointers to instances of MyClass.
return static_cast<MyClass*>((void*)lv.lParam);
}
// ...
private:
// Set to private so users can't modify
// the list view without our consent.
HWND listView;
};
The advantage of this method is that now you have complete control over the list view control and its interface, and thus this will always work (bugs and evil/incompetent programmers notwithstanding). You can even make it a template so that it works with classes other than MyClass
.
You can't check it at all in pure standard C++. You can only do a probabilistic check using the Windows API. So, in practice you can only guarantee it, by making your code correct.
If you could check it you would still not know that it was the correct MyClass
instance.
So, the only good way is to make your code guaranteed correct. That's easier when you limit access to things. C++ has many features to help you limit access, e.g. const
; use them.
Cheers & hth.,
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With