C++ cast to D cast again :)

Bill Baxter dnewsgroup at billbaxter.com
Mon Oct 1 11:42:20 PDT 2007


BLS wrote:
> Bill Baxter schrieb:
>> BLS wrote:
>>> div0 schrieb:
>>>> div0 wrote:
>>>>> BLS wrote:
>>>>>> div0 schrieb:
>>>>>>> BLS wrote:
>>>>>>>> Hi and sorry about picking on your nerves again  :(
>>>>>>>> // C++
>>>>>>>> class CWin
>>>>>>>> {
>>>>>>>> //
>>>>>>>> static LRESULT CALLBACK WndProc(HWND hWnd, UINT uID, WPARAM 
>>>>>>>> wParam, LPARAM lParam)
>>>>>>>> {
>>>>>>>>   CWin* pWnd=NULL;  // init pWnd
>>>>>>>> }
>>>>>>>>
>>>>>>>> // later ...
>>>>>>>> CWin* pChild=reinterpret_cast<CWin*>((HWND)
>>>>>>>> ::GetWindowLong(pWnd->GetDlgItem( ((( LPDRAWITEMSTRUCT 
>>>>>>>> )lParam)->CtlID) ),GWL_USERDATA) );
>>>>>>>>
>>>>>>>>
>>>>>>>> }
>>>>>>>>
>>>>>>>> //our D class
>>>>>>>> class CWin
>>>>>>>> {
>>>>>>>> static LRESULT WndProc(HWND hWnd, UINT uID, WPARAM wParam, 
>>>>>>>> LPARAM lParam)
>>>>>>>> {
>>>>>>>>   CWin pWnd=null;  // init pWnd as    ---reference !
>>>>>>>> }
>>>>>>>> /* instead of :
>>>>>>>> CWin* pChild=reinterpret_cast<CWin*>
>>>>>>>> we use
>>>>>>>> CWin pChild = cast(CWin) cast(void*)
>>>>>>>>
>>>>>>>> But I am not sure how to translate :
>>>>>>>> ((HWND)
>>>>>>>> ::GetWindowLong(pWnd->GetDlgItem( ((( LPDRAWITEMSTRUCT 
>>>>>>>> )lParam)->CtlID) ),GWL_USERDATA) );
>>>>>>>> */
>>>>>>>>
>>>>>>>> // Later we have
>>>>>>>> if (HIWORD(pWnd))
>>>>>>>>
>>>>>>>> /*Since we are working with a ref. instead of a pointer this 
>>>>>>>> will not work.
>>>>>>>> I guess I can use :
>>>>>>>> */
>>>>>>>>
>>>>>>>> if (HIWORD(cast(void*)pWnd))
>>>>>>>> // can you confirm
>>>>>>>> }
>>>>>>>>
>>>>>>>> GetWindowLong() is a Windows Api func., sure you know it.
>>>>>>>> So what the correct translation ?
>>>>>>>> Bjoern
>>>>>>>> Beside, I still wonder : Having a class A, Is A* pA a legal 
>>>>>>>> construct in D.
>>>>>>>> What is pA from a technical view; a pointer to a reference ?
>>>>>>>
>>>>>>> Even if you get this to compile it won't work.
>>>>>>> (well it will till one day until it just crashes mysteriously)
>>>>>>>
>>>>>>> At some point the garbage collector might decide move your Cwin 
>>>>>>> object, invalidating the pointer you are trying to store with 
>>>>>>> SetWindowLong/GetWindowLong.
>>>>>>>
>>>>>>
>>>>>> Thanks div0,
>>>>>> I am allready afraid that this is the case...
>>>>>>
>>>>>>> You'll have to either allocation your cwin objects outside the 
>>>>>>> garbage collectors control or pin the objects. (Don't know how 
>>>>>>> you do this, depends on whether you are using phobos or tango)
>>>>>>>
>>>>>>
>>>>>> Tango.
>>>>>>
>>>>>> What means "pin the object", please explain.
>>>>>> Bjoern
>>>>>
>>>>> Marks the object as not movable.
>>>>> It looks like getAttr/setAttr is what you want, but I've not used 
>>>>> it myself so don't blame me if your program crashes. ;)
>>>>>
>>>>> http://www.dsource.org/projects/tango/browser/trunk/lib/common/tango/core/Memory.d 
>>>>>
>>>>>
>>>>>
>>>>>>
>>>>>>> You should probably look at how dfl interfaces with the Win32 
>>>>>>> API, http://www.dprogramming.com/dfl.ph as that library has 
>>>>>>> solved these issues and you should be able to work out how it's 
>>>>>>> doing all the necessary casting/pinning.
>>>>
>>>> And to actually answer your original question:
>>>>
>>>>
>>>> class CWin {
>>>>     int    m_a;
>>>>
>>>>     this() {
>>>>     }
>>>> }
>>>>
>>>> extern(Windows){
>>>>     typedef void* HWND;
>>>>     int GetWindowLongA(HWND wnd, int indx);
>>>>     int GetWindowLongW(HWND wnd, int indx);
>>>> }
>>>>
>>>>
>>>> void main()
>>>> {
>>>>     // do the call (assume mbcs not unicode)
>>>>     int    r = GetWindowLongA(cast(HWND)0, 0);
>>>>
>>>>     // do the call & cast to CWin object pointer
>>>>     CWin    *pWin = cast(CWin*)GetWindowLongA(cast(HWND)0, 0);
>>>>     Stdout( r );
>>>>     }
>>>>
>>>>
>>>> Replace the 0's with the appropriate values, ie the window handle 
>>>> and GWL_USERDATA (which is -21)
>>>>
>>>> compile with:
>>>>     dmd main.d user32.lib
>>>
>>> We, means Bill B., Regan H., Jarret B. and me have discussed the C++ 
>>> casting to D custing stuff a few days ago. Unfortunately our results 
>>> regarding translating reinterpret_cast<CWin*> are different. Maybe we 
>>> are wrong :(  ... Please have a look at :
>>> http://www.prowiki.org/wiki4d/wiki.cgi?PortingFromCxx
>>
>> I don't think there's anything wrong with cast(T)(cast void*) as a 
>> replacement for C's reinterpret_cast<T> -- ignoring any larger 
>> context.  The issue that div0 is talking about is more global.  If 
>> you're not storing your class pointers as class pointers anywhere then 
>> the garbage collector might not realize there are still live 
>> references and collect the thing prematurely.
>>
> ... Storing your class pointers as class pointers anywhere ...
> Well,
> 
> http://www.digitalmars.com/d/memory.html
> 
> offers some ideas I don't understand. the docs are , in this case, too 
> nitty gritty. qze!lra"lmirmglerhmohmj
> Beeing really nagged and not far away from deleting all D related stuff.

This page would seem to be more relevant:
http://www.digitalmars.com/d/garbage.html (though watch out -- that page 
incorrectly implies that D uses a generational copying collector, which 
it doesn't).

I don't know if you really have a GC problem or not here.  Div0 is at 
least wrong about one thing -- the D GC will not try to move your 
pointer.  D doesn't use that kind of GC.  D's GC never moves pointers. 
It may delete them if it doesn't think they're in use, but it won't move 
them around.  Basically the issue there is just that the GC only 
considers pointer types.  So if you do something like this:

     size_t x = cast(size_t) new MyObject;

It doesn't matter that x holds the address to MyObject.  Since it holds 
that address in a non-pointer type, D doesn't consider it as a potential 
reference to memory.  And if it doesn't consider 'x', then there is 
nothing else that points to that MyObject instance, so the GC will 
collect it.

But BLS, taking a step back, I have to say, if you don't understand how 
the original code works then your chances of successfully porting it 
aren't good.  In general, there will be parts you just have to look and 
and say -- "ok this won't work in D, this part I will rewrite".  You 
have to understand the original code well enough to be able to detect 
those situations, and to rewrite them as needed.

I've given up trying to port different STL containers a couple of times 
now, and the problem always comes down to not understanding the original 
code well enough to rewrite some part of it.  And STL code is so hairy 
that I start thinking it would be faster to go to the library, check out 
a copy of Knuth's Art of Programming, read it, and implement something 
from scratch.

>>> Of course! your comments are welcome.
>>> Bjoern
>>> Beside it is this part :
>>> pWnd->GetDlgItem( ((( LPDRAWITEMSTRUCT ))lParam)->CtlID
>>>
>>> which makes me banging my head on the keyboard ;)
>>
>> looks like just
>>   pWnd.GetDlgItem( (cast(LPDRAWITEMTRUCT)lParam).CtlID )
>>
>> what's the confusion?
>>
>> --bb
> ((still Bad) case) of progammer's confusion. :(
> For sure, C++ is not made for human beeings.

The C++ snippet does have an extra set of parentheses around the 
LPDRAWITEMSTRUCT, so I guess that could be confusing.  And it helps to 
know that in Microsoft-land "LPFOO" is just crazy talk for "FOO*".

--bb


More information about the Digitalmars-d-learn mailing list