WAVEOUTCAPS problem

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hi,

I trying to get something that seems to be simple to work: I’m using VS
2005/C#. I want to get the information of my WaveOut devices. The WAVEOUTCAPS
structure is defined in C++ as:

typedef struct {
WORD wMid;
WORD wPid;
MMVERSION vDriverVersion;
TCHAR szPname[MAXPNAMELEN];
DWORD dwFormats;
WORD wChannels;
WORD wReserved1;
DWORD dwSupport;
} WAVEOUTCAPS;

In C# I declare it as:

public struct WAVEOUTCAPS
{
public ushort wMid;
public ushort wPid;
public ulong vDriverVersion;
public char[] szPname;
public ulong dwFormats;
public ushort wChannels;
public ushort wReserved1;
public ulong dwSupport;
}

And later in the code:

WAVEOUTCAPS waveinfo = new WAVEOUTCAPS();
waveinfo.szPname = new char[32];

the waveOutGetDevCaps function is declared as

[DllImport("winmm.dll")]
public static extern int waveOutGetDevCaps(int uDeviceID, ref WAVEOUTCAPS
lpCaps, int uSize);

everything up to here compiles and runs fine. As soon as I call

waveOutGetDevCaps(0, ref waveinfo, Marshal.SizeOf(waveinfo));

my program crashes with the error:

System.Runtime.InteropServices.SafeArrayTypeMismatchException was unhandled
Message="Specified array was not of the expected type."

Any ideas what I’m doing wrong?
 
[...]
my program crashes with the error:

System.Runtime.InteropServices.SafeArrayTypeMismatchException was
unhandled
Message="Specified array was not of the expected type."

Any ideas what I’m doing wrong?

Maybe you need to explicitly call the Unicode version? The error sure
seems like something that would come up if you tried to pass a C# Unicode
character array to a Win32 ANSI-version function.

I think that the p/invoke stuff should have a way to specify that, but if
not I suppose you could just use "waveOutGetDevCapsW" explicitly.

Pete
 
The problem is that the OP has an array declaration but doesn't specify
that it should be an inline array like the original structure. The array
declaration should be:

[StructLayout(LayoutKind.Sequential)]
public struct WAVEOUTCAPS
{
public ushort wMid;
public short wPid;
public ulong vDriverVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAXPNAMELEN)]
public string szPname;
 
The problem is that the OP has an array declaration but doesn't
specify that it should be an inline array like the original structure.

Ahh. I see that now.

Is it safe to assume that p/invoke will always match up the correct TCHAR
version of a Win32 function? Or are there situations in which that is
actually an issue and needs to be addressed explicitly?
 
It is dependent on the value set to the CharSet property of the
StructLayout attribute assigned to the structure.
 
Thanks. Your post with the sample code was very helpful. I would have never
thought about this.

Nicholas Paldino said:
It is dependent on the value set to the CharSet property of the
StructLayout attribute assigned to the structure.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Peter Duniho said:
Ahh. I see that now.

Is it safe to assume that p/invoke will always match up the correct TCHAR
version of a Win32 function? Or are there situations in which that is
actually an issue and needs to be addressed explicitly?
 
It is dependent on the value set to the CharSet property of the
StructLayout attribute assigned to the structure.

I didn't see that attribute in the original post. That's my point. Can
one rely on the default behavior? Is there a reliable default behavior?
Or is a structure definition without that attribute a bug waiting to be
found?
 
Thanks. Your post with the sample code was very helpful. I would have never
thought about this.

In the future, you might find the pinvoke.net website useful. They
also have an add in to make it easy to get pinvoke signatures directly
from VS.

Chris
 
Well, I would say that it is a bug. Depending on what version of the
API the OP is going to make the call for, it is up to the OP to set that
flag. Generally, when using structures for A or W versions of APIS which
have embedded strings in them which need to be marshaled (using the
ByValTStr UnmanagedType), it would be erroneous to not include the CharSet
property on the attribute definition.
 
Well, I would say that it is a bug. Depending on what version of the
API the OP is going to make the call for, it is up to the OP to set that
flag. Generally, when using structures for A or W versions of APIS which
have embedded strings in them which need to be marshaled (using the
ByValTStr UnmanagedType), it would be erroneous to not include the
CharSet
property on the attribute definition.

Okay...thanks! Good to know. :)
 
Back
Top