Can't solve this CallBack returning structures

M

MyAlias

Can't solve this CallBack returning structures

Error message:
An unhandled exception of type 'System.NullReferenceException'
occurred in MyTest.exe
Additional information: Object reference not set to an instance of an
object.

Situation skeleton:
Private Declare Function EnumFontFamiliesASCII Lib "gdi32" Alias
"EnumFontFamiliesA" (ByVal hdc As Integer, ByVal lpszFamily As Integer,
ByVal lpEnumFontFamProc As effp, ByVal lParam As Integer) As Integer
Delegate Function effp(ByRef lpNLF As LOGFONT, ByRef lpNTM As
NEWTEXTMETRIC, ByVal FontType As Integer, ByRef lParam As Integer) As
Integer
Private Function EnumFontFamProc(ByRef lpNLF As LOGFONT, ByRef lpNTM
As NEWTEXTMETRIC, ByVal FontType As Integer, ByRef lParam As Integer) As
Integer
' MyNonRelatedCode here
return 1
End Function

Public Function EnumFontFamilies() As String()
Dim shdc As Integer = GetDC(0)
-> EnumFontFamiliesASCII(shdc, 0, AddressOf EnumFontFamProc, 0)
Call ReleaseDC(0, shdc)
End Function

The error occurs at line signaled by '->'

Error cause from the top level view:
The windows does not care about the NET framework, it does not notify
that the structures lpNLF and lpNTM where initialized

Why do I say that?:
Because there is no error when replacing in effp and EnumFontFamProc
ByRef lpNLF As LOGFONT, ByRef lpNTM As NEWTEXTMETRIC
by
ByVal lpNLF As Integer, ByVal lpNTM As Integer


What is the Attribute to use or any other workarround if available?


Thanks for taking you time
 
K

Ken Tucker [MVP]

Hi,

Best work around

Dim ff As FontFamily
For Each ff In FontFamily.Families
Debug.WriteLine(ff.Name)
Next

Ken
 
M

MyAlias

May you explain how does your solution apply to microsoft windows
callbacks returning structures?
 
T

Tom Shelton

Can't solve this CallBack returning structures

Error message:
An unhandled exception of type 'System.NullReferenceException'
occurred in MyTest.exe
Additional information: Object reference not set to an instance of an
object.

Situation skeleton:
Private Declare Function EnumFontFamiliesASCII Lib "gdi32" Alias
"EnumFontFamiliesA" (ByVal hdc As Integer, ByVal lpszFamily As Integer,
ByVal lpEnumFontFamProc As effp, ByVal lParam As Integer) As Integer

This is my first impression :)

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Private Structure LOGFONT
Public lfHeight As Integer
Public lfWidth As Integer
Public lfEscapement As Integer
Public lfOrientation As Integer
Public lfWeight As Integer
Public lfItalic As Byte
Public lfUnderline As Byte
Public lfStrikeOut As Byte
Public lfCharSet As Byte
Public lfOutPrecision As Byte
Public lfClipPrecision As Byte
Public lfQuality As Byte
Public lfPitchAndFamily As Byte

<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=LF_FACESIZE)> _
Public lfFaceName As String
End Structure

....

Private Delcare Auto Function EnumFontFamilies lib "gdi32" _
(ByVal hdc As IntPtr, _
ByVal lpszFamily As String, _
ByVal lpEnumFontFamProc As effp, _
ByVal lpParam As IntPtr) As Integer


Private Declare Function GetDC Lib "user32" _
(ByVal hWnd As IntPtr) As IntPtr

Private Declare Function ReleaseDC Lib "user32" _
(ByVal hWnd As IntPtr, _
ByVal hDC As IntPtr) As Integer
Delegate Function effp(ByRef lpNLF As LOGFONT, ByRef lpNTM As
NEWTEXTMETRIC, ByVal FontType As Integer, ByRef lParam As Integer) As
Integer

Delegate Function effp _
(ByRef lpelf As LOFFONT, _
ByRef lpntm As NEWTEXTMETRIC, _
ByVal FontType As Integer, _
ByVal lParam As IntPtr) As Integer

Private Function EnumFontFamProc( _
ByRef lpNLF As LOGFONT, _
ByRef lpNTM As NEWTEXTMETRIC, _
ByVal FontType As Integer, _
ByRef lParam As Integer) As Integer

' MyNonRelatedCode here
return 1
End Function


Public Function EnumFontFamilies() As String()
Dim shdc As IntPtr = GetDC(IntPtr.Zero)

' very important - keep a reference to you're
' delegate, or GC may snatch it from you
Dim cb As New effp(AddressOf EnumFontFamProc)

EnumFontFamilies( _
shdc, _
Nothing, _
cb, _
IntPtr.Zero)

Call ReleaseDC(IntPtr.Zero, shdc)
End Function

HTH
 
M

MyAlias

Thanks for your attention

NEWTEXTMETRIC only has Integers and Bytes, no problem
The problem appears for arrays
LOGFONT has lfFaceName(LF_FACESIZE) As Byte
the solution I got from another declaration is to marshall:
<MarshalAsAttribute(UnmanagedType.ByValArray,
SizeConst:=LF_FACESIZE)> lfFaceName() As Byte


I don't know what parameters to use for marshalling structures inside
structures.


I got this unsolved:


Private Structure WCRANGE
Dim wcLow As Short
Dim cGlyphs As Short
End Structure

Private Structure GLYPHSET
Dim cbThis As Integer
Dim flAccel As Integer
Dim cGlyphsSupported As Integer
Dim cRanges As Integer
OK-> <MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst:=100)> Dim
ranges() As Integer
End Structure

what marshall parameters to use to declare
ranges() As WCRANGE
instead of
ranges() As Integer
in order to have EXACTLY the same memory contents?
 
M

MyAlias

:)
Thats the solution I partially found after 8 hours
I believe your code will work completely


If you still have time, could you tell me how to get a NET form's hdc?
I tried GetDC and CreateDC but this generates an error.
I need the hDC to list font properties such as GetFontUnicodeRanges


Another marshalling problem:

Private Structure WCRANGE
Dim wcLow As Short
Dim cGlyphs As Short
End Structure

Private Structure GLYPHSET
Dim cbThis As Integer
Dim flAccel As Integer
Dim cGlyphsSupported As Integer
Dim cRanges As Integer
OK-> <MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst:=100)> Dim
ranges() As Integer
End Structure

what marshall parameters to use to declare
ranges() As WCRANGE
instead of
ranges() As Integer
in order to have exactly the same memory contents?

Thanks for taking your time
 
T

Tom Shelton

:)
Thats the solution I partially found after 8 hours
I believe your code will work completely

Well, I'm glad you found an answer... Wish I had seen it earlier :)
If you still have time, could you tell me how to get a NET form's hdc?
I tried GetDC and CreateDC but this generates an error.
I need the hDC to list font properties such as GetFontUnicodeRanges

Dim g As Graphics = Me.CreateGraphics()
Dim hDC As IntPtr = g.GetHdc()

' do stuff with the hDC

' make sure you clean up the graphics object
g.Dispose()
Another marshalling problem:

Private Structure WCRANGE
Dim wcLow As Short
Dim cGlyphs As Short
End Structure

Private Structure GLYPHSET
Dim cbThis As Integer
Dim flAccel As Integer
Dim cGlyphsSupported As Integer
Dim cRanges As Integer
OK-> <MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst:=100)> Dim
ranges() As Integer
End Structure

what marshall parameters to use to declare
ranges() As WCRANGE
instead of
ranges() As Integer
in order to have exactly the same memory contents?

Thanks for taking your time

I answered this in another thread, but the short answer is you can't...
The current .NET marshaller doesn't support arrays of structs in structs.
You'll need to pass it in as integers, and then break them up manually
after the call...

I think, but I haven't confirmed that this will be added in 2.0.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top