Jump to content

Help with a structure for a DLL


Recommended Posts

Hello,

I am new to the forum as a member, although I have been visiting for years, as I have been programming in AutoIT for a long time, and I have learned a lot from the postings here.

I am trying to work with a DLL: the eSpeak API, which is a speech synthesizer.

To create the AutoIT code, I am following the next header file:

 

eSpeak NG header file

 

The problem lies in the following structure:

 

typedef struct {
    espeak_EVENT_TYPE type;
    unsigned int unique_identifier; // message identifier (or 0 for key or character)
    int text_position;    // the number of characters from the start of the text
    int length;           // word length, in characters (for espeakEVENT_WORD)
    int audio_position;   // the time in mS within the generated speech output data
    int sample;           // sample id (internal use)
    void* user_data;      // pointer supplied by the calling program
    union {
        int number;        // used for WORD and SENTENCE events.
        const char *name;  // used for MARK and PLAY events.  UTF8 string
        char string[8];    // used for phoneme names (UTF8). Terminated by a zero byte unless the name needs the full 8 bytes.
    } id;
} espeak_EVENT;

 

 

 

Specifically with the union, since I don't know very well how this structure would be written with this union, in AutoIT.

I have seen in the forum some similar example, although simpler. But I don't know if it would be the same in this case: I know that the size of the union, is the size of the biggest of its members, and for what I have seen in some code of example, it would be enough to put then the element of bigger size.

But I think that this way it would not be possible to access all the members of the union (maybe I'm wrong).

On the other hand, I don't know if it would be correct to put all the members of the union in the structure, as if they were part of this one, in DLLStructCreate().
I don't know if it would work, because I haven't started coding the functions yet, as I'm defining constants, enumerations and structures initially and I'm stuck here.

Also, I've read that on 64-bit Windows, things can get complicated, because of data alignment (which I know nothing about): the DLL is 32-bit, but I would use it on 64-bit Windows.

So I'm in a mess, and I don't know how to do correctly this structure in AutoIT.

I would appreciate if someone can help me, and put me the code, to understand it better, and see if I'm on the right track with the theory I have about the joins or not.

Also, as I only master a little C, I don't know if "const char *" refers to a string (I understand it does). That being so, this parameter, I guess it would be "str" in AutoIT right?

Thanks, and sorry if my writing is not very good, as I am not English!

 

Link to comment
Share on other sites

Unions in Autoit can be tricky.  I learned the hard way in my HTTPAPI UDF.  To give credit where credit is due, @Danyfirex is the one that helped me understand it.

Of course, I don't have a way to test this other than how I did it in the example below.  The tricky part is getting the alignment of the union correct.  As you sort of stated, the size of the largest data type in the union determines the union's alignment.  And whether you are running as 32 or 64 bit can make a difference.  In 32-bit mode, the largest data type in your union is 4 bytes.  So the alignment should start on a multiple of 4.  The size of the struct before the union, in 32-bit mode, is 28 bytes.  Since 28 is a multiple of 4, no alignment adjustment needs to be done.  The size of the struct, in 64-bit mode, is 32 bytes and the largest union data type is 8 bytes.  So, again, no adjustment to the alignment needs to be done.

Again, I haven't been able to test it to make sure that I have everything correct, but I think it looks right.  Also, there's more than 1 way to do this in AutoIt.  This is just the way that I chose because it seems the most straight forward.  This should work in both 32 & 64 bit scripts.

So when you implement it in your real script, you would use the appropriate struct (WORD/SENTENCE, MARK/PLAY, or NAME) depending on the event type you are working with.

 

#AutoIt3Wrapper_AU3Check_Parameters=-w 3 -w 4 -w 5 -w 6 -d
#AutoIt3Wrapper_UseX64=N  ;N = 32-bit / Y = 64-bit

#include <Constants.au3>
#include <WinAPIDiag.au3>


#cs
    typedef struct {
        espeak_EVENT_TYPE type; //ENUM
        unsigned int unique_identifier; // message identifier (or 0 for key or character)
        int text_position;    // the number of characters from the start of the text
        int length;           // word length, in characters (for espeakEVENT_WORD)
        int audio_position;   // the time in mS within the generated speech output data
        int sample;           // sample id (internal use)
        void* user_data;      // pointer supplied by the calling program
        union {
            int number;        // used for WORD and SENTENCE events.
            const char *name;  // used for MARK and PLAY events.  UTF8 string
            char string[8];    // used for phoneme names (UTF8). Terminated by a zero byte unless the name needs the full 8 bytes.
        } id;
    } espeak_EVENT;
#ce

;ESPEAK EVENT BASE STRUCT
Global $gtag_ESPEAK_EVENT = _
           "struct;"              & _
           "int   type;"          & _
           "uint  uid;"           & _
           "int   textPosition;"  & _
           "int   length;"        & _
           "int   audioPosition;" & _
           "int   sample;"        & _
           "ptr   userData;"      & _
           "endstruct;"

;ESPEAK ID UNION STRUCTs
Global $gtag_ESPEAK_EVENT_UNION_ID_INT = _
           "struct;"              & _
           "int   id;"            & _
           "endstruct;"
Global $gtag_ESPEAK_EVENT_UNION_ID_PTR = _
           "struct;"              & _
           "ptr   id;"            & _
           "endstruct;"
Global $gtag_ESPEAK_EVENT_UNION_ID_CHAR = _
           "struct;"              & _
           "char   id[8];"        & _
           "endstruct;"

;ESPEAK EVENT STRUCTs with Unions
Global $gtag_ESPEAK_EVENT_WORD_SENTENCE = _
           $gtag_ESPEAK_EVENT         & _
           $gtag_ESPEAK_EVENT_UNION_ID_INT
Global $gtag_ESPEAK_EVENT_MARK_PLAY = _
           $gtag_ESPEAK_EVENT          & _
           $gtag_ESPEAK_EVENT_UNION_ID_PTR
Global $gtag_ESPEAK_EVENT_NAME = _
           $gtag_ESPEAK_EVENT         & _
           $gtag_ESPEAK_EVENT_UNION_ID_CHAR


example()

Func example()
    Local $tEspeakEvent

    $tEspeakEvent = DllStructCreate($gtag_ESPEAK_EVENT)
    If @error Then Exit MsgBox($MB_ICONERROR + $MB_TOPMOST, "ERROR", "Error creating $gtag_ESPEAK_EVENT - @error = " & @error)
    _WinAPI_DisplayStruct($tEspeakEvent,$gtag_ESPEAK_EVENT, "ESPEAK_EVENT_" & (@AutoItX64 ? " 64bit" : " 32bit"))

    $tEspeakEvent = DllStructCreate($gtag_ESPEAK_EVENT_WORD_SENTENCE)
    If @error Then Exit MsgBox($MB_ICONERROR + $MB_TOPMOST, "ERROR", "Error creating $gtag_ESPEAK_EVENT_WORD_SENTENCE - @error = " & @error)
    _WinAPI_DisplayStruct($tEspeakEvent,$gtag_ESPEAK_EVENT_WORD_SENTENCE, "ESPEAK_EVENT_WORD_SENTENCE" & (@AutoItX64 ? " 64bit" : " 32bit"))

    $tEspeakEvent = DllStructCreate($gtag_ESPEAK_EVENT_MARK_PLAY)
    If @error Then Exit MsgBox($MB_ICONERROR + $MB_TOPMOST, "ERROR", "Error creating $gtag_ESPEAK_EVENT_MARK_PLAY - @error = " & @error)
    _WinAPI_DisplayStruct($tEspeakEvent,$gtag_ESPEAK_EVENT_MARK_PLAY, "ESPEAK_EVENT_MARK_PLAY" & (@AutoItX64 ? " 64bit" : " 32bit"))

    $tEspeakEvent = DllStructCreate($gtag_ESPEAK_EVENT_NAME)
    If @error Then Exit MsgBox($MB_ICONERROR + $MB_TOPMOST, "ERROR", "Error creating $gtag_ESPEAK_EVENT_NAME - @error = " & @error)
    _WinAPI_DisplayStruct($tEspeakEvent,$gtag_ESPEAK_EVENT_NAME, "ESPEAK_EVENT_NAME" & (@AutoItX64 ? " 64bit" : " 32bit"))
EndFunc

 

Edited by TheXman
Corrected an error in my original script. No alignment adjustment is needed in this case.
Link to comment
Share on other sites

Thank you very much for the code. I will study it and implement it in my code. And as soon as I can test it, I will tell you if it has worked for me.

Precisely, the thing that confuses me with the unions in AutoIT, is that of the alignment; that having never done it, I do not understand it very well (I know what it refers to, but not how it works internally).

 

I suppose that the line:

#AutoIt3Wrapper_AU3Check_Parameters=-w 3 -w 4 -w 5 -w 6 -d

 

It doesn't influence for the operation of the structure does it. Because I don't usually use

that parameter

I have never seen this way to create structures in AutoIT, with struct and endstruct, which seem to be members of the structure? But it looks like a way to define a struct block, like if and endstruct.

 

It is that I usually use an old AutoIT reference help (version 3.3.6) in Spanish, which is my language, and it does not appear this in DLLStructCreate()

 

I will have to study well this code, because I do not finish to understand why several structures are created, and why to use one or another one... Being all in a single C++ structure, I guess the eSpeak API will need it to be like that in AutoIT as well.

 

Thanks!

 

Link to comment
Share on other sites

2 hours ago, Jonny37 said:

I will have to study well this code, because I do not finish to understand why several structures are created, and why to use one or another one..

Several structures are created because the union could have several different data formats.

Depending on the value of the type element, the union could either contain an

1) integer

2) pointer to a char

3) array of 8 chars

so depending on what the type value is for a given record, you use the right struct to be able to interpret the bytes of the union correctly.

Also, and btw, @TheXman really went beyond the call of duty on this one.  If there was just someway in this forum to show him appreciation besides saying “Thanks!, now would be the time to find it 👉👉👉 👉👉👉👉👉👉👉👇

Edited by JockoDundee
miscalculated alignment of hand pointers

Code hard, but don’t hard code...

Link to comment
Share on other sites

2 hours ago, Jonny37 said:

I suppose that the line: #AutoIt3Wrapper_AU3Check_Parameters=-w 3 -w 4 -w 5 -w 6 -d

It doesn't influence for the operation of the structure does it. Because I don't usually use that parameter

Aside : I do not think, that these parameters will affect the operation, see :

·     -q         : quiet mode (this will only show errors and warnings)
·     -d         : set the "MustDeclareVars" option to True
·     -w 1      : give a warning if an include file is included more than once
·     -w 2      : give a warning if #comments-end (or #ce) is missing
·     -w 3      : give a warning if variables are already declared
·     -w 4      : give a warning if local variables are used in the global scope
·     -w 5      : give a warning if a local variable is declared but not used
·     -w 6      : give a warning when using Dim
·     -w 7      : give a warning if ByRef parameters are incorrect

Musashi-C64.png

"In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move."

Link to comment
Share on other sites

True, it is true. I had not realized how the union works, where all its members share the same memory area; and I had not thought about how to access each of the members: I was only thinking about how to create the structure with the nested union.

As soon as I can, I will try it, since the first function (espeak_Initialize()) is not making it easy for me, since when I call it, the AutoIT program closes and I don't know why.

If it still does not work, I will open another thread to see if you can help me with this.

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...