Jump to content

Dll issues


Recommended Posts

Hello folks,

I am currently designing a dll using C++, which I would like to work in AutoIt as well as other programming languages. I am using the stdcall calling convention, and all the calls work fine in the latest AutoIt beta with the stac checking, but only those that return numbers. As soon as I try to return a character string, or an AutoIt str if you will, it crashes with the stac error message refering me to the help file. The string function is declared in the exact same way as the ones that return numbers, and since I am the one writing the dll I know for a fact that all the parameters are right. As other people have stated before, some dll's that worked in previous versions of AutoIt no longer run properly, which is the case with my own dll. At first I thought that it must be a problem with my code as I am no expert in C++. But then I tried with the WinMM dll, returning a name of a Midi device. This worked fine in earlier AutoIt betas, andI assume that the Microsoft dll is compiled perfectly right with the stdcall method. Is it so that whenever a string is returned, cdecl must be used? By tweaking the AutoIt code a bit and making it use cdecl rather than stdcall for the string functions I can get it to work, but is this really nesessary? Shouldn't it be possible to just use one single calling convention and not have to mix cdecl and stdcall? My dll works fine in Visual Basic 6 for instance, as well as in earlier AutoIt versions like I said before. But then again, it might still be a problem with my code. But if that is the case I don't see why the Microsoft dll wouldn't work, since the native Win32 dll's all use stdcall as far as I know. If it turns out that the only way to solve this is to always use cdecl when a string is returned I suppose that it will have to be that way, but if there is anything that I could be doing wrong I would appreciate some feedback.

Regards

Philip Bennefall

Link to comment
Share on other sites

Hello folks,

I am currently designing a dll using C++, which I would like to work in AutoIt as well as other programming languages. I am using the stdcall calling convention, and all the calls work fine in the latest AutoIt beta with the stac checking, but only those that return numbers. As soon as I try to return a character string, or an AutoIt str if you will, it crashes with the stac error message refering me to the help file. The string function is declared in the exact same way as the ones that return numbers, and since I am the one writing the dll I know for a fact that all the parameters are right. As other people have stated before, some dll's that worked in previous versions of AutoIt no longer run properly, which is the case with my own dll. At first I thought that it must be a problem with my code as I am no expert in C++. But then I tried with the WinMM dll, returning a name of a Midi device. This worked fine in earlier AutoIt betas, andI assume that the Microsoft dll is compiled perfectly right with the stdcall method. Is it so that whenever a string is returned, cdecl must be used? By tweaking the AutoIt code a bit and making it use cdecl rather than stdcall for the string functions I can get it to work, but is this really nesessary? Shouldn't it be possible to just use one single calling convention and not have to mix cdecl and stdcall? My dll works fine in Visual Basic 6 for instance, as well as in earlier AutoIt versions like I said before. But then again, it might still be a problem with my code. But if that is the case I don't see why the Microsoft dll wouldn't work, since the native Win32 dll's all use stdcall as far as I know. If it turns out that the only way to solve this is to always use cdecl when a string is returned I suppose that it will have to be that way, but if there is anything that I could be doing wrong I would appreciate some feedback.

Regards

Philip Bennefall

Auto3Lib maps many of the Windows API calls and I have not had any problem with returning strings. My understanding of the latest changes to DllCall are that the developers put code in to detect a corrupted stack. You can corrupt the stack and the call will still work, it will just bite you in the back side later on in your code. What the developers have done is actually a blessing, as they're pin pointing the source of all those wierd problems that happened 3 or 4 function calls after DllCall was used.

Not being able to see your Dll source or your method of calling your Dll will only leave me guessing, but if I had to guess, I would say that you are having problems with pointers or your Dll is corrupting the stack itself. Just guesses though and only meant to give you something else to look at.

Auto3Lib: A library of over 1200 functions for AutoIt
Link to comment
Share on other sites

Thank you for your quick reply and helpful hints. Here's something for you to look at which might make it possible for you to determine whether or not my dll is at fault or if it is AutoIt. Like I said, the Winmm.dll call didn't work either in the latest beta.

I declare my functions like so:

#define exporting __declspec( dllexport )

extern "C" exporting const char* __stdcall PbTalker_GetInputDeviceName(int);

I don't think there should be a problem with that, but I don't know for certain of course.

Regards

Philip Bennefall

Link to comment
Share on other sites

Thank you for your quick reply and helpful hints. Here's something for you to look at which might make it possible for you to determine whether or not my dll is at fault or if it is AutoIt. Like I said, the Winmm.dll call didn't work either in the latest beta.

I declare my functions like so:

#define exporting __declspec( dllexport )

extern "C" exporting const char* __stdcall PbTalker_GetInputDeviceName(int);

I don't think there should be a problem with that, but I don't know for certain of course.

Regards

Philip Bennefall

How about posting the code that you used for WinMM.dll? We know that WinMM.dll is OK, so that only leaves two things. AutoIt or the way you're calling the Dll. Since I have a passing knowledge of how to use DllCall, I may be able to narrow it down for you.
Auto3Lib: A library of over 1200 functions for AutoIt
Link to comment
Share on other sites

Here is the function that I made, to retrieve a midi device name:

Func get_midi_out_device_name($ID)

; Create a struct used to store the name and some other information about the device.

$output_struct = DLLStructCreate("dword;dword;char[256]")

; Make the dll call.

$return = DLLCall($winmmdll,"int","midiOutGetDevCaps","int",$ID,"ptr",DLLStructGetPtr($output_struct),"int",DLLStructGetSize($output_struct))

If Not IsArray($return) Then

; Free the struct.

$output_struct = 0

SetError(-1)

Return

EndIf

$return = $return[0]

If $return <> 0 Then

; The return value was something other than 0, which means that an error occured.

; Free the struct.

$output_struct = 0

SetError($return)

Return

EndIf

; Retrieve the data and then free the struct before returning.

$data = DLLStructGetData($output_struct,3)

$output_struct = 0

Return $data

EndFunc

This code worked fine in previous AutoIt versions. Here is how I call the function in my own dll to get the name of an input audio device:

$devname = DLLCall($pbtalker,"str","PbTalker_GetInputDeviceName","int",0)

This also worked fine in previous AutoIt versions. I bet I'm making a really stupid mistake of some kind, I just don't know what it is. The dll I'm developing will allow a developer to add voicechat capabilities into their application really easily, making use of Port audio, Winsock and Speex.

Regards

Philip Bennefall

Link to comment
Share on other sites

Here is the function that I made, to retrieve a midi device name:

Func get_midi_out_device_name($ID)

; Create a struct used to store the name and some other information about the device.

$output_struct = DLLStructCreate("dword;dword;char[256]")

; Make the dll call.

$return = DLLCall($winmmdll,"int","midiOutGetDevCaps","int",$ID,"ptr",DLLStructGetPtr($output_struct),"int",DLLStructGetSize($output_struct))

If Not IsArray($return) Then

; Free the struct.

$output_struct = 0

SetError(-1)

Return

EndIf

$return = $return[0]

If $return <> 0 Then

; The return value was something other than 0, which means that an error occured.

; Free the struct.

$output_struct = 0

SetError($return)

Return

EndIf

; Retrieve the data and then free the struct before returning.

$data = DLLStructGetData($output_struct,3)

$output_struct = 0

Return $data

EndFunc

This code worked fine in previous AutoIt versions. Here is how I call the function in my own dll to get the name of an input audio device:

$devname = DLLCall($pbtalker,"str","PbTalker_GetInputDeviceName","int",0)

This also worked fine in previous AutoIt versions. I bet I'm making a really stupid mistake of some kind, I just don't know what it is. The dll I'm developing will allow a developer to add voicechat capabilities into their application really easily, making use of Port audio, Winsock and Speex.

Regards

Philip Bennefall

Oh my! Where to start. :shocked: The prototype for midiOutGetDevCaps is:

MMRESULT midiOutGetDevCaps(
  UINT_PTR    uDeviceID,      
  LPMIDIOUTCAPS lpMidiOutCaps,  
  UINT        cbMidiOutCaps   
);

The MIDIOUTCAPS structure is defined as:

typedef struct { 
    WORD      wMid; 
    WORD      wPid; 
    MMVERSION vDriverVersion; 
    CHAR      szPname[MAXPNAMELEN]; 
    WORD      wTechnology; 
    WORD      wVoices; 
    WORD      wNotes; 
    WORD      wChannelMask; 
    DWORD    dwSupport; 
} MIDIOUTCAPS;

And your definition of MIDIOUTCAPS is:

$output_struct = DLLStructCreate("dword;dword;char[256]")oÝ÷ Ù8Z¶gÍX¢íý­ë¬x*º]Âݪê-«{*.².Ö޺ȧ«¨¶Èh®Ú®¢Ý¢é¢²Çuçâ)à¼:â½êÕz»"¢}ÁyÆ®±ê¶nÞÊ·ö·¬µêixZ/z»3>v¦{só@0BÄ6+7Úz-Û¸bÙ÷ö×(^µëazËk¹Ën­ç^~)â¶*'Âg̨»kz¬²)ධ®à½©nz)ÜlÈë­    ªlN©®^­×x­ß¢³L JÈhºW`¢Ê&zØb   bëaˬx'{.¶-mëZ­é^jǺÚ"µÍÝXÝÜX]][ÝÜÚÜÓZYÜÚÜÔYÝZ[]Ú[ÛØÚÞ[YVÌÌNÜÚÜÕXÚÛÙÞNÜÚÜÕÚXÙÎÜÚÜÓÝÎÜÚÜÐÚ[[XÚÎÙÛÜÔÝÜ   ][ÝÊoÝ÷ Øh¯zØb±«kɩݱç¢*.®ènW¦²
Á¬Ø­ý°!­¶¡yÉú+(§~Ú¦§tw«{*.®¶­sd6öç6öÆUw&FRvWEöÖFö÷WEöFWf6UöæÖRfײ5" ¤gVæ2vWEöÖFö÷WEöFWf6UöæÖRb33c´B¢Æö6Âb33c·D62Âb33c¶&W@ ¢b33c·D62ÒFÆÅ7G'V7D7&VFRgV÷C·6÷'BtÖC·6÷'BuC·VçBdG&fW%fW'6öã¶6"7¥æÖU³3%Ó²gV÷C²fײð¢gV÷C·6÷'BuFV6æöÆöw·6÷'Bufö6W3·6÷'Btæ÷FW3·6÷'Bt6ææVÄÖ6³¶Gv÷&BGu7W÷'BgV÷C²¢b33c¶&WBÒFÆÄ6ÆÂgV÷CµväÔÒæFÆÂgV÷C²ÂgV÷C¶çBgV÷C²ÂgV÷C¶ÖF÷WDvWDFWd62gV÷C²ÂgV÷C¶çBgV÷C²Âb33c´BÂgV÷C·G"gV÷C²ÂFÆÅ7G'V7DvWEG"b33c·D62ÂgV÷C·VçBgV÷C²ÂFÆÅ7G'V7DvWE6¦Rb33c·D62¢bb33c¶&WE³ÒfÇC²fwC²FVâ&WGW&â6WDW'&÷"ÓÂÓÂgV÷C²gV÷C²¢&WGW&âb33c·D62ç7¥æÖP¤VæDgVæ
Edited by PaulIA
Auto3Lib: A library of over 1200 functions for AutoIt
Link to comment
Share on other sites

You're absolutely right, that definition is completely wrong. It was something that I put together really quickly just to see if I could do it. But it worked in the early betas, so I thought "what the heckI'll keep it". I apologise for the crappy code, it's very old and I didn't know anything at all about dll structs at the time. That was before I learned C++. But why my own dll doesn't work, I can't say. Could I maybe send it to you via email and you could try it out? I would be very glad if you could give it a go and see if you can figure anything out.

Regards

Philip Bennefall

Link to comment
Share on other sites

Oh, I'm sorry; I should've started it in support to begin with rather than in bug reports since I'm not a hundred percent sure that it is actually a bug. My apologies.

Regards

Philip Bennefall

I don't think it's a bug, but it may have something to do with returning a string pointer as the result. I can't think of any Windows API calls that do this. The standard is to pass a buffer pointer to the function that is used to return the string. You might just want to convert your function to this style and skip the headaches since we know that AutoIt can handle this.
Auto3Lib: A library of over 1200 functions for AutoIt
Link to comment
Share on other sites

But if it's not a bug, how come it worked in the earlier betas and no more? Also, the function that you changed does not work either, I replaced my old one with your new modification. Still no luck.

Regards

Philip Bennefall

Like I said before, the new version of AutoIt has been changed to detect stack corruption, and your function was obviously corrupting the stack. The fact that you had bad code that used to work and now doesn't, isn't the issue. Think of it as the AutoIt developers fixing a bug that allowed your bad code to run and now it's up to you to fix your code.

No offense, but you're pointing your finger at everybody else to try to explain the problems that your having. I've developed a library that has hundreds of API calls in it and I know a little bit about what I'm talking about. I've shown you that you didn't have the midi call correct either. I think it's time you slow down and consider that the problems that you're having may be self induced.

I tested the code that I posted and it works just fine on the two machines I ran it on. If you're truly having problems with the code, then you need to be specific about what those problems are. However, I think you're going to find in the end that you've made another mistake somewhere. The only other possiblity is that your machine is screwed up or you don't have the correct version of AutoIt.

Auto3Lib: A library of over 1200 functions for AutoIt
Link to comment
Share on other sites

My intention was not to point my finger at anyone, simply to try and figure out what was wrong. I'm sorry if it sounded as if I was bitching about the whole thing, I was merely trying to understand if AutoIt or my code was at fault. I've been messing around a little with my export table and I now have a temporary sollution for handling it, which makes it work with the sdcall method in AutoIt. I'm not sure if it is a good method, but that's outside the scope of this forum since it has to do with C++ and not AutoIt.

Thank you for all your information on the issue, now I understand more how the dll call function operates and what to avoid when designing stuff in the future. Again, I don't think my temporary sollution is perfect but it will do for testing purposes.

Regards

Philip Bennefall

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