How do I marshall a pointer over SendMessage LPARAM or WPARAM?

Cross-posted from Haskell-beginners. Apologies for not posting in the right place (though I am a beginner and have probably made a simpleton error). I'm new to Haskell, and have had some good success with FFI so far, but using Win32's sendMessage to send a pointer in LPARAM or WPARAM is resulting in access violations at the other end. Is there some issue with my pointer conversions? Am I hitting some restriction, or missing some compiler options? It's driving me pretty crazy, after a very nice start to using Haskell. Some "sending" code: Foreign.C.String.withCWString "frustrator" $ \s -> do let wParam = System.Win32.Types.castPtrToUINT s :: System.Win32.Types.WPARAM Graphics.Win32.sendMessage wnd Graphics.Win32.wM_APP wParam 0 wndProc "receiving" code: | wmsg == Graphics.Win32.wM_APP = do s <- peekCWString $ System.Win32.Types.castUINTToPtr wParam putStrLn s return 0 The string will not be seen. Some extra notes: I can get wndProc messages and integral data generally. The pointer values match textually at both ends when "shown" to stdout. At the sending side I can pass the CWString to a regular FFI function call just fine, and castUINTToPtr will give me back a functioning Ptr for that call. I have also tried sending to & receiving from a working C++ program, without success. Access violations are reported when receiving, though again the address matches up. Silence from Haskell as before, when C++ is sending. I found someone else having an issue here: http://osdir.com/ml/haskell-cafe@haskell.org/2009-11/msg00731.html but no solution unfortunately. UPDATE since prior posting: Seems if I call out via FFI on the sending side, and set the WPARAM to L"hardcoding FTW" in a wrapper C function, the SendMessage I then invoke will work. The C code sees both the original string and the new one, but only the second works when used. I must be missing something obvious, but have toasted my grey cells at this point!

On Wed, 2012-07-18 at 18:22 +0200, Simon Peter Nicholls wrote:
Some "sending" code:
Foreign.C.String.withCWString "frustrator" $ \s -> do let wParam = System.Win32.Types.castPtrToUINT s :: System.Win32.Types.WPARAM Graphics.Win32.sendMessage wnd Graphics.Win32.wM_APP wParam 0
wndProc "receiving" code:
| wmsg == Graphics.Win32.wM_APP = do s <- peekCWString $ System.Win32.Types.castUINTToPtr wParam putStrLn s return 0
From the docs ( http://hackage.haskell.org/packages/archive/base/4.5.1.0/doc/html/Foreign-C-... ):
the memory is freed when the subcomputation terminates (either normally or via an exception), so the pointer to the temporary storage must not be used after this
I'm noy a windows guru, but I assume that `sendMessage` just puts the message into a queue and exits. So, you receive a pointer to already deallocated memory.

Sorry Yuras, I missed this.
It turns out that I made a mistake when trying to pinpoint my problem.
I had started out using WM_COPY_DATA and COPYDATASTRUCT, but upon
facing issues, tried simple sending of a C string and a WM_APP
message. However, that simplifying resulted in me losing the memory
mapping needed for copying data.
(for anyone facing similar woes)
The use of WM_COPY_DATA and COPYDATASTRUCT in combination are
essential, since Windows performs memory mapping to ensure the data
being "copied" is available to the receiving process:
WM_COPY_DATA message is received by Windows.
It's handled as a special case, and COPYDATASTRUCT is inspected.
cbData worth of bytes are memory mapped for the lpData content.
A WM_COPY_DATA message will be received in your wndProc function, with
an appropriate COPYDATASTRUCT for the memory mapped content.
It's fine to use withTString (and similar) in combination with
sendMessage, since the IO will be syncronous.
cbData for a TString can be calculated by string length * size of a
System.Win32.Types.TCHAR, accounting for end of string sentinel.
withTStringLen can also be used, but be aware that the zero terminator
will not be present, and I'm not sure if the "Len" given by that
function is string length, or byte count. I wanted a regular
terminated c string, and so haven't tried it.
On Wed, Jul 18, 2012 at 7:29 PM, Yuras Shumovich
On Wed, 2012-07-18 at 18:22 +0200, Simon Peter Nicholls wrote:
Some "sending" code:
Foreign.C.String.withCWString "frustrator" $ \s -> do let wParam = System.Win32.Types.castPtrToUINT s :: System.Win32.Types.WPARAM Graphics.Win32.sendMessage wnd Graphics.Win32.wM_APP wParam 0
wndProc "receiving" code:
| wmsg == Graphics.Win32.wM_APP = do s <- peekCWString $ System.Win32.Types.castUINTToPtr wParam putStrLn s return 0
From the docs ( http://hackage.haskell.org/packages/archive/base/4.5.1.0/doc/html/Foreign-C-... ):
the memory is freed when the subcomputation terminates (either normally or via an exception), so the pointer to the temporary storage must not be used after this
I'm noy a windows guru, but I assume that `sendMessage` just puts the message into a queue and exits. So, you receive a pointer to already deallocated memory.
participants (2)
-
Simon Peter Nicholls
-
Yuras Shumovich