From: John McCabe on
Guys

Thought I might as well add it to this thread, but I'm now having a
slight problem running with Win32Ada.

The basis of the code I'm using is in my "please review my code"
thread.

Essentially I've got the code shown below the double dashed line
(well, that's most of it).

When I run it, the Read_And_Print_Patches call _before_ outputting the
output device information is fine, but the same call _after_
outputting the output device information fails. Sometimes it just
prints the "1" prior to the Ada.Text_IO.Open call, and sometimes I get
PROGRAM_ERROR EXCEPTION_ACCESS_VIOLATION.

Now, if I change the declarations of Midi_In_Caps and Midi_Out_Caps
to:

Midi_In_Caps : aliased Win32.Mmsystem.MIDIINCAPS;
Midi_Out_Caps : aliased Win32.Mmsystem.MIDIOUTCAPS;

and use 'Unchecked_Access in the calls to midiInGetDevCaps and
midiOutGetDevCaps for those objects (and dispose of the Free calls) it
seems to work ok. That sounds like some memory isn't being allocated
properly somehow. I can't see that I'm doing anything wrong but if you
can please let me know.

One thing I noticed though is that in mmsystem.h (in the
i686-pc-mingw32 folder) the declaration of MIDIINCAPS (well,
MIDIINCAPSA as it's non-Unicode) is:

typedef struct tagMIDIINCAPSA {
WORD wMid;
WORD wPid;
MMVERSION vDriverVersion;
CHAR szPname[MAXPNAMELEN];
DWORD dwSupport;
} MIDIINCAPSA,*PMIDIINCAPSA,*LPMIDIINCAPSA;

However in win32-mmsystem.ads, the corresponding definition is:

type MIDIINCAPSA is -- mmsystem.h:835
record
wMid : Win32.WORD; -- mmsystem.h:836
wPid : Win32.WORD; -- mmsystem.h:837
vDriverVersion : MMVERSION; -- mmsystem.h:838
szPname : Win32.CHAR_Array (0 .. 31); -- mmsystem.h:839
end record;

Now call me stupid if you like, but does it not look like there's
something missing there? (i.e. the dwSupport field).

If anyone can be bothered to check this out and see what they think
your comments would be appreciated, especially if you can spot that
I've done something stupid.

Do you think this is a bug that AdaCore should know about if they
don't already?

Obviously I could go down the route of not using dynamic memory
because, as I mentioned, it seems to work that way, but I don't like
not knowing why it didn't work the other way!

=================================
-- File: MidiDevs.adb
with Ada.Text_IO;
with Ada.Unchecked_Deallocation;

with Interfaces.C;
use type Interfaces.C.Unsigned;

with Win32.Mmsystem;
use type Win32.Mmsystem.MMRESULT;

with TestFileRead;

procedure MidiDevs is
Num_Input_Devices : Win32.UINT;
Num_Output_Devices : Win32.UINT;

res : Win32.Mmsystem.MMRESULT;
Midi_In_Caps : Win32.Mmsystem.LPMIDIINCAPS;
Midi_Out_Caps : Win32.Mmsystem.LPMIDIOUTCAPS;

procedure Free is new
Ada.Unchecked_Conversion(Win32.Mmsystem.LPMIDIINCAPS,
Win32.Mmsystem.MIDIINCAPS);
procedure Free is new
Ada.Unchecked_Conversion(Win32.Mmsystem.LPMIDIOUTCAPS,
Win32.Mmsystem.MIDIOUTCAPS);

package UINT_Text_IO is new
Ada.Text_IO.Modular_IO(Win32.UINT);
package MM_Text_IO is new
Ada.Text_IO.Modular_IO(Win32.Mmsystem.MMRESULT);

begin
Num_Input_Devices := Win32.Mmsystem.midiInGetNumDevs;
Num_Output_Devices := Win32.Mmsystem.midiOutGetNumDevs;

Ada.Text_IO.Put("There are ");
UINT_Text_IO.Put(Num_Input_Devices, 0);
Ada.Text_IO.Put(" input devices available, and ");
UINT_Text_IO.Put(Num_Output_Devices, 0);
Ada.Text_IO.Put_Line(" output devices available.");

Midi_In_Caps := new Win32.Mmsystem.MIDIINCAPS;
Midi_Out_Caps := new Win32.Mmsystem.MIDIOUTCAPS;

if Num_Input_Devices > 0
then
Ada.Text_IO.New_Line;
Ada.Text_IO.Put("The ");
UINT_Text_IO.Put(Num_Input_Devices, 0);
Ada.Text_IO.Put_Line(" input devices are:");
Ada.Text_IO.New_Line;

for Device_ID in Win32.UINT range 0..(Num_Input_Devices - 1)
loop
res := Win32.Mmsystem.midiInGetDevCaps(Device_ID,
Midi_In_Caps,

Win32.Mmsystem.MIDIINCAPS'size
* Win32.BYTE'size);
UINT_Text_IO.Put(Device_ID, 0);
Ada.Text_IO.Put(") ");
if res = Win32.Mmsystem.MMSYSERR_NOERROR
then
Ada.Text_IO.Put("szPname = ");

Ada.Text_IO.Put_Line(Interfaces.C.To_Ada(Win32.To_C(Midi_In_Caps.szPname)));
else
Ada.Text_IO.Put("Query Failed. Returned ");
MM_Text_IO.Put(res, 0);
end if;
Ada.Text_IO.New_Line;
end loop;
end if;

-- Try reading in the file
TestFileRead.Read_And_Print_Patches;
Ada.Text_IO.New_Line;

if Num_Output_Devices > 0
then
Ada.Text_IO.New_Line;
Ada.Text_IO.Put("The ");
UINT_Text_IO.Put(Num_Output_Devices, 0);
Ada.Text_IO.Put_Line(" output devices are:");
Ada.Text_IO.New_Line;

for Device_ID in Win32.UINT range 0..(Num_Output_Devices - 1)
loop
res := Win32.Mmsystem.midiOutGetDevCaps(Device_ID,
Midi_Out_Caps,

Win32.Mmsystem.MIDIOUTCAPS'size
* Win32.BYTE'size);
UINT_Text_IO.Put(Device_ID, 0);
Ada.Text_IO.Put(") ");
if res = Win32.Mmsystem.MMSYSERR_NOERROR
then
Ada.Text_IO.Put("szPname = ");

Ada.Text_IO.Put_Line(Interfaces.C.To_Ada(Win32.To_C(Midi_Out_Caps.szPname)));
else
Ada.Text_IO.Put("Query Failed. Returned ");
MM_Text_IO.Put(res, 0);
end if;
Ada.Text_IO.New_Line;
end loop;
end if;

-- Try reading in the file
TestFileRead.Read_And_Print_Patches;
Ada.Text_IO.New_Line;

Free(Midi_In_Caps);
Free(Midi_Out_Caps);

end MidiDevs;
===================
=================================
-- File: TestFileRead.ads
package TestFileRead is
procedure Read_And_Print_Patches;
end TestFileRead;
===================
=================================
-- File: TestFileRead.adb
with Ada.Text_IO;

package body TestFileRead is
----------------------------
-- Read_And_Print_Patches --
----------------------------
procedure Read_And_Print_Patches is
Input_File : Ada.Text_IO.File_Type;
begin
Ada.Text_IO.Put_Line("1");
-- Note: You need a file that exists
Ada.Text_IO.Open(SysEx_File,
Ada.Text_IO.In_File,
"FILENAME.TXT");
Ada.Text_IO.Put_Line("2");
Ada.Text_IO.Close(Input_File);
Ada.Text_IO.Put_Line("3");
end Read_And_Print_Patches;

end TestFileRead;
===========

From: John McCabe on
John McCabe <john(a)nospam.assen.demon.co.uk.nospam> wrote:

Couple of corrections....

1) I've put Unchecked_Conversion where it should be
Unchecked_Deallocation. Replace:

> procedure Free is new
> Ada.Unchecked_Conversion(Win32.Mmsystem.LPMIDIINCAPS,
> Win32.Mmsystem.MIDIINCAPS);
> procedure Free is new
> Ada.Unchecked_Conversion(Win32.Mmsystem.LPMIDIOUTCAPS,
> Win32.Mmsystem.MIDIOUTCAPS);

With

procedure Free is new
Ada.Unchecked_Deallocation(Win32.Mmsystem.MIDIINCAPS,
Win32.Mmsystem.LPMIDIINCAPS);

procedure Free is new
Ada.Unchecked_Deallocation(Win32.Mmsystem.MIDIOUTCAPS,
Win32.Mmsystem.LPMIDIOUTCAPS);


2) In face, the replacing with aliased Win32.Mmsystem.MIDIINCAPS etc
and use of Unchecked_Access DOESN'T WORK. It stops the file open from
failing, but the calls to midiIn/OutGetDevCaps return MMRESULT value
11 whish is Invalid Parameter.

Ah well.

I've done some more searching, and it looks to me like basically the
Win32Ada binding that AdaCore are allowing people to download are a
minimum of 11 years old. Apparently the last intermetrics version
(3.0) was released in 1999. The win32-mmsystem.ads has an Intermetrics
copyright date of 1995.

This is rather unfortunate. I'd hope this would be very useful for
what I wanted to do but, to be honest, it looks like the idea is
doomed as I really don't want to have to re-create a whole set of
Win32 Ada bindings based on the existing MinGW versions of these files
(that also appear to be out of date compared to the definitions of the
types you can find on Microsoft's website).

Disappointing.
John
From: tmoran on
> One thing I noticed though is that in mmsystem.h (in the
> i686-pc-mingw32 folder) the declaration of MIDIINCAPS (well,
> MIDIINCAPSA as it's non-Unicode) is:
>
> typedef struct tagMIDIINCAPSA {
> WORD wMid;
> WORD wPid;
> MMVERSION vDriverVersion;
> CHAR szPname[MAXPNAMELEN];
> DWORD dwSupport;
> } MIDIINCAPSA,*PMIDIINCAPSA,*LPMIDIINCAPSA;
>
> However in win32-mmsystem.ads, the corresponding definition is:
>
> type MIDIINCAPSA is -- mmsystem.h:835
> record
> wMid : Win32.WORD; -- mmsystem.h:836
> wPid : Win32.WORD; -- mmsystem.h:837
> vDriverVersion : MMVERSION; -- mmsystem.h:838
> szPname : Win32.CHAR_Array (0 .. 31); -- mmsystem.h:839
> end record;

> I've done some more searching, and it looks to me like basically the
> Win32Ada binding that AdaCore are allowing people to download are a
> minimum of 11 years old. Apparently the last intermetrics version
> (3.0) was released in 1999. The win32-mmsystem.ads has an Intermetrics
> copyright date of 1995.

Looking at an mmsystem.h dated 8/21/96 I see

typedef struct tagMIDIINCAPSA {
WORD wMid; /* manufacturer ID */
WORD wPid; /* product ID */
MMVERSION vDriverVersion; /* version of the driver */
CHAR szPname[MAXPNAMELEN]; /* product name (NULL terminated string) */
#if (WINVER >= 0x0400)
DWORD dwSupport; /* functionality supported by driver */
#endif
} MIDIINCAPSA,*PMIDIINCAPSA,*LPMIDIINCAPSA;

Do you need to access dwSupport? If not, do you need to allocate space for
a record of this type, or do you just use pointers to a record allocated
by mmsystem?
From: John McCabe on
John McCabe <john(a)nospam.assen.demon.co.uk.nospam> wrote:

>Guys

<..snip..>

>Now call me stupid if you like, <..snip..>

You're stupid - glad it was me who spotted it though :-) Sudden flash
of inspiration at ~6:00am....

> res := Win32.Mmsystem.midiInGetDevCaps(Device_ID,
> Midi_In_Caps,
>
>Win32.Mmsystem.MIDIINCAPS'size
> * Win32.BYTE'size);

It would probably help if I wasn't asking for the Midi_In_Caps
structure to be filled in with 64x the amount it should be. I should
be dividing by Win32.BYTE'Size here, not multiplying.

Still doesn't get round the issue with win32-mmsystem,h but, in answer
to Tom (later), I don't need the dwSupport field on the IN side as
it's always zero.

John