Jonny37 Posted May 7, 2021 Share Posted May 7, 2021 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 More sharing options...
TheXman Posted May 7, 2021 Share Posted May 7, 2021 (edited) 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. expandcollapse popup#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 May 10, 2021 by TheXman Corrected an error in my original script. No alignment adjustment is needed in this case. JockoDundee, Danyfirex, pixelsearch and 1 other 4 CryptoNG UDF: Cryptography API: Next Gen jq UDF: Powerful and Flexible JSON Processor | jqPlayground: An Interactive JSON Processor Xml2Json UDF: Transform XML to JSON | HttpApi UDF: HTTP Server API | Roku Remote: Example Script About Me How To Ask Good Questions On Technical And Scientific Forums (Detailed) | How to Ask Good Technical Questions (Brief) "Any fool can know. The point is to understand." -Albert Einstein "If you think you're a big fish, it's probably because you only swim in small ponds." ~TheXman Link to comment Share on other sites More sharing options...
Jonny37 Posted May 8, 2021 Author Share Posted May 8, 2021 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 More sharing options...
JockoDundee Posted May 8, 2021 Share Posted May 8, 2021 (edited) 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 May 8, 2021 by JockoDundee miscalculated alignment of hand pointers TheXman and Musashi 2 Code hard, but don’t hard code... Link to comment Share on other sites More sharing options...
Musashi Posted May 8, 2021 Share Posted May 8, 2021 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 TheXman and JockoDundee 2 "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 More sharing options...
Jonny37 Posted May 8, 2021 Author Share Posted May 8, 2021 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 More sharing options...
JockoDundee Posted May 8, 2021 Share Posted May 8, 2021 2 hours ago, Jonny37 said: If it still does not work, I will open another thread to see if you can help me with this. Thanks, we would appreciate a second chance... Code hard, but don’t hard code... Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now