views:

441

answers:

3

Hello, I am writing multi-thread socket chat in C++Builder 2009.
It is almost complete in accordance with what I need to do but I have a little problem. I need to pass the TMemo* pointer into CreateThread WinAPI function which upcasts it to void*.

I tryed this way:

HANDLE xxx = MemoChat->Handle;
hNetThread = CreateThread(NULL, 0, NetThread, xxx, 0, &dwNetThreadId);
//...

and then, in NetThread function,

TMemo* MyMemo((HANDLE)lpParam);
TMemo* MyMemo((TMemo*)lpParam);

but it didn`t work:(

The question is how I can really downcast it correctly so I can use my Memo Component in this new thread?

+2  A: 

Please understand that a HANDLE is not a pointer, but a concept of the Win32 API. So the first line casts the LPVOID to HANDLE - this is correct, as the parameter of the thread routine really is given as a handle (xxx). However, it then goes on converting the HANDLE to a MyMemo object; this treats the bits in the handle as if they would form an address - which they aren't.

The second line does exactly the same conversion - it treats a handle as if it were a pointer directly.

I wonder why you aren't passing MemoChat itself to the thread:

hNetThread = CreateThread(NULL, 0, NetThread, MemoChat, 0, &dwNetThreadId);
Martin v. Löwis
Handle is not a win 32 thing. A handle is a well defined computer science concept. It is a pointer t a pointer. Where the second pointer is under system control. Thus allowing the system to dynamically move memory blocks without effecting the holder of the handle.
Martin York
See http://msdn.microsoft.com/en-us/library/ms724457(VS.85).aspx. "Each handle has an entry in an internally maintained table." The Win32 HANDLE is a specific implementation of the general CS handle concept.
Martin v. Löwis
I thought, that was exactly what I said before!
Martin York
A HANDLE is *not* a pointer, despite it being a typedef for void*. A *pointer* is an address in memory. A HANDLE is an opaque value; most often, it is an *index* (not a pointer) into the process' handle table.
Martin v. Löwis
I think you splitting hairs over implementation details and missing the point. However it is implemented, consider it a pointer (or indirect reference) to a pointer. As such it can be used as a pointer in this context (it is after all just a glorified void* or LPVOID). Try it it will work fine :-)
Martin York
+3  A: 

Call:

TMemo*     MemoChat   = // You defined that somewhere I assume
HANDLE     hNetThread = CreateThread(NULL, 0, NetThread, MemoChat, 0, &dwNetThreadId);

What is happening here is that any pointer you pass as the third parameter is being auto converted into a void pointer (or in WinTerms LPVOID). That's fine it does not change it it just loses the type information as the system does not know anything about your object.

The new Thread Start point:

DWORD NetThread(LPVOID lpParameter)
{
    TMemo*   MemoChat   = reinterpret_cast<TMemo*>(lpParameter);
    // Do your thread stuff here.
}

Once your thread start method is called. Just convert the void pointer back into the correct type and you should be able to start using it again.

Just to clear up other misconceptions.

A HANDLE is a pointer.
And you could have passed it as the parameter to the NetThread().

A HANDLE is a pointer to pointer under system control which points at the object you are using. So why the double indirection. It allows the system to move the object (and update its pointer) without finding all owners of the object. The owners all have handles that point at the pointer that was just updated.

It is an old fashioned computer science concept that is used infrequently in modern computers because of the OS/Hardware ability to swap main memory into secondary storage. but for certain resource they are still useful. Nowadays when handles are required they are hidden inside objects away from the user.

Martin York
I thought that it`s better never use reintepret_cast. So, your post means I`m wrong.:)
chester89
Yes it is best never to use reinterpret_cast<>(), but this is one of the few situations that you have to use it. The fact that you need to use it, shows that things can go terribly wrong and you should carefully check that you are really casting to the correct type.
Martin York
thanks for comments, it helped a lot
chester89
Not 100% sure you have *windows* handles right. see below.
Roddy
Pointer, indirect reference. Same thing :-)
Martin York
A: 

This is more to try and clarify the handle vs. pointer thing, because I don't think Martin has it exactly right.

A "pointer to a pointer" is indeed called a HANDLE, and is a common CS approach to allowing the operating system to physically move heap-allocated memory blocks around without the explicit knowledge of an application layer, which always accesses them via handles. Classic 68K Mac OS works in this way. OS'es that work in this way typically allow user code to allocate memory via handles as well as directly off the heap. This approach is used on machines that don't have proper memory-management hardware.

However,there are other uses of the word HANDLE which borrow the some of the abstraction of the previous use, but with different implementations. Opaque pointers (pointers to datastructures of which the user has no knowledge - PIMPL idiom) are also commonly called HANDLES.

Also, the term HANDLE can be used simply to denote a "reference" to an object - maybe an index into an array. Unix File Handles (= file descriptors) are a good example of this. stdin=0,stdout=1,...

So, which of the above are Windows API HANDLES? I've seen conflicting reports. This document says:

Handles in Win32 are numbers used to identify resources or windows. They are not pointers or pointers to pointers. Think of them as ID numbers.

Roddy
In Win32, a HANDLE (which is the actual name of the typedef) is most definitely not a pointer (i.e. a memory address). Instead, it is an opaque value - for kernel handles, it's an index (into a table living in kernel memory). See http://www.cs.miami.edu/~burt/journal/NT/handle_table.html
Martin v. Löwis
It is an indirect reference. Same concept different implementation.
Martin York
@Martin v. Lowis. Thanks - nice link. Windows confuses the issue by having "typedef void* HANDLE".
Roddy
@Martin Y: Agreed - but your answer is pushing the "pointer-to-pointer" implementation as the only one , and implying that's how windows works. Unless, of course, we disagree on what constitutes a pointer... ;-)
Roddy