Sign in to follow this  
Followers 0
Andreik

Data type in structure

11 posts in this topic

I have a struct like this one:

typedef struct
{
    char        *Name;
    int      X;
    int      Y;

} MyStruct;

an array like this one:

MyStruct MyArray[] =
{
    {"Item1", 50, 24},
    {"Item2", 60, 22}
};

and a function:

extern "C" __declspec(dllexport) int MyFunc(int *NumOfItems, MyStruct **pArray)
{
    *NumOfItems   = sizeof(MyArray)/sizeof(MyStruct);
    *pArray = MyArray;
    return 1;
}

My question is how should I create the properly structure in AutoIt to can call MyFunc. I'm very confuse if I should use something like

Global Const $tagMyStruct = "ptr;int;int;"
Global $MyStruct, $Struct

$NumOfItems = DllStructCreate("int")
$StructPtr = DllStructCreate("ptr")
DllCall("Test.dll","int:cdecl","MyFunc","int",DllStructGetPtr($NumOfItems),"ptr",DllStructGetPtr($StructPtr))

For $Index = 1 To DllStructGetData($NumOfItems,1)
    $Struct &= $tagMyStruct
Next
$MyStruct = DllStructCreate($Struct,DllStructGetData($StructPtr,1))
$Name1 = DllStructCreate("char[64]",DllStructGetData($MyStruct,1)) ;char[64] - big enough to get the name
$Name2 = DllStructCreate("char[64]",DllStructGetData($MyStruct,4)) ;char[64] - big enough to get the name
MsgBox(0,"Items",DllStructGetData($Name1,1) & @CRLF & DllStructGetData($Name2,1))
or instead of ptr in $tagMyStruct can I use something some kind of char[]?

When the words fail... music speaks

Share this post


Link to post
Share on other sites



You can't use char arrays directly, as described in this example. This would be how i would do it, so you have a managed array instead of a large struct:

Global Const $tagMyStruct = "ptr;int;int;"
Global Const $sizeOfMyStruct = DllStructGetSize(DllStructCreate($tagMyStruct))
Global Const $tagCharArr = "char[64]"

$Result = DllCall("Test.dll","int:cdecl","MyFunc","int*",0,"int*",0) ;breaks on x64 beware
; Result [1] should contain NumOfItems, and Result[2] should contain pointer to first MyStruct.
; Now we make an array of them.
If @Error then Exit -1

Global $pArray[$Result[1] + 1] ;Array is 1-based with first index as size

For $i = 1 to $Result[1]
    $pArray[$i] = DllStructCreate($tagMyStruct,$Result[2] + (($i - 1) * $sizeOfMyStruct))
    ;Similar to pArray[i] = (MyStruct*) result[2] + i * sizeof(Mystruct)
Next

$pArray[0] = $result[1]

;And know you can do:

For $i = 1 to $pArray[0]
    ConsoleWrite("x = " & DllStructGetData($pArray[$i],2) & ", y = " & DllStructGetData($pArray[$i],3) & @CRLF)
    ;Since autoit doesn't support char arrays like that, we have to create a temporary struct to extract:
    ConsoleWrite(@Tab & "name = " DllStructGetData(DllStructCreate($tagCharArr,DllStructGetData($pArray[$i],1))) & @LF)
Next

Ever wanted to call functions in another process? ProcessCall UDFConsole stuff: Console UDFC Preprocessor for AutoIt OMG

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

I have a question, working with a little project in autoit (Specifically the scite editor clone) gave me some insight into how to make gui applications in C++, suddenly I found myself understanding (a little) some basics but now I'm having trouble with datatypes.

when compiling this code, I get an "Invalid conversion from Char* to BOOL". Well, by what I can tell is that the message is correct of course and I don't know how to have this function return the data string "as is".

BOOL DoFileOpen(HWND hwnd) {
    OPENFILENAME ofn;
    char szFileName[MAX_PATH];

    ZeroMemory(&ofn, sizeof(ofn));
    szFileName[0] = 0;

    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFilter = "Text Files (*.txt)0*.txt0All Files (*.*)0*.*00";
    ofn.lpstrFile = szFileName;
    ofn.nMaxFile = MAX_PATH;
    ofn.lpstrDefExt = "txt";


    ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
    if(GetOpenFileName(&ofn)) {
        MessageBox(hwnd, szFileName, "Name", MB_OK | MB_ICONEXCLAMATION);
        return szFileName;//<-- Problem right here
    }
    return 0;
}

What am I missing? :idiot:

Edited by ApudAngelorum

Things that I've done..

Icon Resource Editor: icon resource editor 

AutoIt Piano: a piano

AutoIt Unlocker: unlocks files when you want to delete them

Colorful tooltips: a wrapper for the tool tips UDF

Rouge GoogleBot: a full screen animation

ASciTE text editor: a text editor written in autoit

Warning: Posts by this user are subject to change or may disappear without notice.

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Oh, whoops.

I guess I just found out that you declare the return type in the function name...

CHAR* DoFileOpen() {
    OPENFILENAME ofn;
    char szFileName[MAX_PATH];//<-- warning: address of local variable 'szFileName' returned

    ZeroMemory(&ofn, sizeof(ofn));
    szFileName[0] = 0;

    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = NULL;
    ofn.lpstrFilter = "Text Files (*.exe)0*.exe0All Files (*.*)0*.*00";
    ofn.lpstrFile = szFileName;
    ofn.nMaxFile = MAX_PATH;
    ofn.lpstrDefExt = "txt";

    ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
    if(GetOpenFileName(&ofn)) {
        return szFileName;
    }
    return 0;
}

But now I'm getting undefined reference to `GetOpenFileNameA@4'

Although, it is working in one project with a simple GUI, but not in another...

Edit: Damn it, I just looked into the compiler options and noticed the other project was a Console app, changing it to GUI application stopped giving me these errors.

But I am getting a warning - warning: address of local variable 'szFileName' returned

What am I doing wrong now?

Edited by ApudAngelorum

Things that I've done..

Icon Resource Editor: icon resource editor 

AutoIt Piano: a piano

AutoIt Unlocker: unlocks files when you want to delete them

Colorful tooltips: a wrapper for the tool tips UDF

Rouge GoogleBot: a full screen animation

ASciTE text editor: a text editor written in autoit

Warning: Posts by this user are subject to change or may disappear without notice.

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

If you want to return a string you have to globally allocate the required memory and free it if you have finished using it, e.g. use malloc / free:

char *szFileName = (char*) malloc(MAX_PATH+1);
...
free(szReturnedPath);
Edited by ProgAndy

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Share this post


Link to post
Share on other sites

If you want to return a string you have to globally allocate the required memory and free it if you have finished using it, e.g. use malloc / free:

char *szFileName = (char*) malloc(MAX_PATH+1);
...
free(szReturnedPath);

I see now, thanks. I stopped getting the error but now I'm left wondering about some stuff I was reading where an article mentioned that the function "malloc" was a C function and that in C++ you would use the "new" keyword.

http://www.codeproject.com/Articles/14746/Multithreading-Tutorial

Second paragraph down.

In the C language, you use malloc to acquire memory from the heap, and in C++, you use the new keyword.


Things that I've done..

Icon Resource Editor: icon resource editor 

AutoIt Piano: a piano

AutoIt Unlocker: unlocks files when you want to delete them

Colorful tooltips: a wrapper for the tool tips UDF

Rouge GoogleBot: a full screen animation

ASciTE text editor: a text editor written in autoit

Warning: Posts by this user are subject to change or may disappear without notice.

Share this post


Link to post
Share on other sites

If you really want to return pointer to allocated memory then you would use neither new or malloc. When that is the case you have to be precise what method should be used to free memory, i.e. you have to be precise about how that memory is allocated.

Operator new does not dictate the way memory is allocated. That is implementation detail for/of specific compiler.

There are better ways of doing all this, for example asking for pointer to allocated memory by the caller.

1 person likes this

♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

Or using a string object so you don't have to worry about memory management at all.

Also, ProgAndy, you say "globally allocate" but that's not true and means something entirely different (and bad) than what's need. All that's necessary in this case is to ensure the object lifetime is correct, it doesn't need to be global for that.

Share this post


Link to post
Share on other sites

You are both right. I just went for a quick and dirty solution in C and did not read the post completely. A buffer supplied per parameter (plain C), or string objects (when using C++) are the better choice.

1 person likes this

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

asking for pointer to allocated memory by the caller.

I think I have an idea of what you mean?

char* DoFileOpen(char path[]) {
OPENFILENAME ofn;
ZeroMemory(&ofn, sizeof(ofn));

ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = NULL;
ofn.lpstrFilter = "Executable (*.exe)0*.exe0All Files (*.*)0*.*00";
ofn.lpstrFile = path;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrDefExt = "exe";

ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
if(GetOpenFileName(&ofn)) {
MessageBox(0, path, "Name", MB_OK | MB_ICONEXCLAMATION);
return path;
}
return 0;
}

Like this? It doesn't give me an error an it seems to work.

I just pass it as a parameter after its creation in the calling function right?

char szFileName[MAX_PATH]; is created in the calling function instead.

But one thing I'm not understanding is why the File open dialog will not come up if I comment out this line~

szFileName[0] = 0;

After declaring the variable, by what I know in autoit, something like this would usually assign 0 to the first index of the array but obviously something else is happening there....

Edited by ApudAngelorum

Things that I've done..

Icon Resource Editor: icon resource editor 

AutoIt Piano: a piano

AutoIt Unlocker: unlocks files when you want to delete them

Colorful tooltips: a wrapper for the tool tips UDF

Rouge GoogleBot: a full screen animation

ASciTE text editor: a text editor written in autoit

Warning: Posts by this user are subject to change or may disappear without notice.

Share this post


Link to post
Share on other sites

You should not be using the Windows API yet. You still know far too little about what you are attempting to do.

Share this post


Link to post
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
Sign in to follow this  
Followers 0