Jump to content

Data type in structure


Andreik
 Share

Recommended Posts

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.

Link to comment
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

Link to comment
Share on other sites

  • 3 months later...

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
Link to comment
Share on other sites

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
Link to comment
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);
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

Link to comment
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.

Link to comment
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.

Link to comment
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.

Link to comment
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.

*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

Link to comment
Share on other sites

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
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...