none
How to use DrawTextEx (really, how to mix managed and unmanaged code) RRS feed

  • Question

  • Sorry if this question is too basic. I'm new to mixing managed and unmanaged code and the documentation is making my head spin.  Basically I need to call DrawTextEx from a Windows Forms application (using visual c++).  The TextRenderer class was working just great until I tried adjusting the tab stops, which it doesn't do.  Apparently I need to hit the Windows API directly.

    After a crash course in marshaling and P/Invoke, I managed to cobble together the following:

    [StructLayout(LayoutKind::Sequential)]
    value class RECT
    {
    public: int left;
    	  int top;
    	  int right;
    	  int bottom;
    };
    
    [StructLayout(LayoutKind::Sequential)]
    value class DRAWTEXTPARAMS
    {
    public: unsigned int cbSize;
    		int iTabLength;
    		int iLeftMargin;
    		int iRightMargin;
    		unsigned int uiLengthDrawn;
    };
    
    [DllImport("user32.dll")]
    extern int DrawTextEx(
    	IntPtr hDc, 
    	[In, Out, MarshalAs(UnmanagedType::LPTStr)]
    	String^ string, 
    	int stringLength, 
    	[In, Out, MarshalAs(UnmanagedType::Struct)]
    	RECT rect, 
    	unsigned int dwDTFormat, 
    	[In, MarshalAs(UnmanagedType::Struct)]
    	DRAWTEXTPARAMS params);
    

    And my actual call looks like this (though I don't think the problem is with the call):

    DrawTextEx(e->Graphics->GetHdc(), se->text, se->text->Length, MyRect, DT_EXPANDTABS | DT_TABSTOP, dtParams);
    

    se->text is a String, MyRect is a RECT as defined above, and dtParams is a DRAWTEXTPARAMS as defined above.  The two constants in there are defined as unsigned ints, 64 and 128 respectively, according to some reference I found somewhere.

    The code does compile, but when I run the application, as soon as it hits the DrawTextEx call it throws an exception:

    A call to PInvoke function 'Mabel!<Module>::DrawTextEx' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

    As near as I can tell, the managed and unmanaged function signatures match, but I'm really not very knowledgeable about this.  Any help would be greatly appreciated.

    -Jeremy

    ps. I also tried throwing in a CallingConvention modification with the DllImport attribute, but I kept getting compiler errors about the 'CallingConvention' attribute not being recognized, so I gave up and got rid of it.

    Wednesday, May 11, 2011 3:07 AM

Answers

  • Looking at the signature of DrawTextEx that you have defined, for the second parameter you have rightly used String^ string because the Windows API has a long pointer. Similarly should you be using RECT^ rect and DRAWTEXTPARAMS^ params ? Because the corresponging windows API again has long pointers to these structures.

    • Marked as answer by JeremyW76 Thursday, May 12, 2011 9:50 PM
    Wednesday, May 11, 2011 4:01 AM

All replies

  • Looking at the signature of DrawTextEx that you have defined, for the second parameter you have rightly used String^ string because the Windows API has a long pointer. Similarly should you be using RECT^ rect and DRAWTEXTPARAMS^ params ? Because the corresponging windows API again has long pointers to these structures.

    • Marked as answer by JeremyW76 Thursday, May 12, 2011 9:50 PM
    Wednesday, May 11, 2011 4:01 AM
  •   The TextRenderer class was working just great until I tried adjusting the tab stops, which it doesn't do. 


    If ExpandTabs wouldn't do what  you want, did you try DrawString with a StringFormat?
    Wednesday, May 11, 2011 6:23 AM
  • Yes, thank you!  That did the trick. I redefined my RECT and DRAWTEXTPARAMS classes as ref classes rather than value classes, and marshaled them as UnmanagedType::LPStruct.  Sure enough, it compiles and runs without complaint.  (Now to get the text formatting properly -- yeesh... looks like I need to dig even deeper into this stuff).  Thanks again for the help.

    -Jeremy

    Thursday, May 12, 2011 9:55 PM