If I create a DLL that returns a string to ms-access, ms-access 'stops working' and crashes. If I convert the string to a double, then the DLL works fine an ms-access does not crash. I also suspect that the DLL remains loaded after the calling script has terminated however this could be by design. Closing ms-access stops the DLL. It is a minor pest having to open and close ms-access everytime I need to recompile the DLL. No being able to pass strings is a serious limitation.
I am using ms-access 2010 32 bit on Win 7 x64. Code that can be used to test for the bug is located in a post on EXIF data extraction from photos. http://www.purebasic.fr/english/viewtop ... 2&start=15
Return string from PureBasic DLL function crashes ms-access
Re: Return string from PureBasic DLL function crashes ms-acc
On close investigation, the issue is not a PureBasic bug, rather it is bad information in the PB help file. According to a MicroSofts MSDN web site at DLL can only return a number as a function return which explains why I can get the DLL to work with numbers. In the case of strings, the DLL can change the value of the string but cannot return the string as a function return. Any function return from a DLL that changes a string will be a number and the number can be used to indicate something like the length of the new string. When as string is passed to a DLL, it is always passed by reference and a DLL may change this string. As the string has been passed by reference, it will also be changed within ms-access or ms-excel. Just use the string variable that was passed to the DLL as it will now have a changed value. No function return value from the DLL call is required. There are some other factors, the string that is passed to the DLL must be terminated with a null character, so you have to add vbNullChar to the end of your string before passing it from Excel or Access (I have not tested if PB handles this yet). Secondly, the string that has been passed has to be large enough to handle the changed value, so you may need to add several null characters to the end of your string to make it long enough to handle any change.
In summary, calls to functions in DLLs work if a number is expected as a return value. Getting a DLL to change a string works differently. I have not tested whether I can use a DLL to change a string yet with the string being later used in ms-access. The purpose of this post was to indicate the source of the issue. The information in the Help File for PB works for DLL functions that return numbers. It does not work for functions that work with strings.
The full explanation is here http://msdn.microsoft.com/en-us/library ... e.10).aspx in an Offce Dev Centre article called "Returning Strings from DLL Functions". Here are the breadcrumbs that lead to the article. "Office development > Office desktop > Office XP > Office XP Developer > Microsoft Office XP Developer > Programming Concepts > The Windows API and Other Dynamic-Link Libraries > Calling DLL Functions > Returning Strings from DLL Functions"
In summary, calls to functions in DLLs work if a number is expected as a return value. Getting a DLL to change a string works differently. I have not tested whether I can use a DLL to change a string yet with the string being later used in ms-access. The purpose of this post was to indicate the source of the issue. The information in the Help File for PB works for DLL functions that return numbers. It does not work for functions that work with strings.
The full explanation is here http://msdn.microsoft.com/en-us/library ... e.10).aspx in an Offce Dev Centre article called "Returning Strings from DLL Functions". Here are the breadcrumbs that lead to the article. "Office development > Office desktop > Office XP > Office XP Developer > Microsoft Office XP Developer > Programming Concepts > The Windows API and Other Dynamic-Link Libraries > Calling DLL Functions > Returning Strings from DLL Functions"
Re: Return string from PureBasic DLL function crashes ms-acc
I would like to get string operations working, namely to pass a string from ms-access to pb, change the string in pb and then get the changed string back in ms-access. Here is some test code that I am working to identify the issue. I have not worked with pointers before so the problem lies here.
PB DLL code with 3 versions of the same procedure. Issues are described in comments.
Here is the calling code which need to be places in a standard module in ms-access. It only calls the last procedure in the above code.
===VBA===
===End VBA===
I can't get this working. Need help.
Andrew M
PB DLL code with 3 versions of the same procedure. Issues are described in comments.
Code: Select all
Global MyString$
Global InputString$
ProcedureDLL.d StringChangerD (InputString$)
;Works but returns a number and does not change string as the string was provided by Value and not as a reference.
;Need to change the input to a memory address - too hard for me
success.d
MessageRequester( "test",InputString$)
MyString$ = "Hello to you too"
If Len(InputString$) > Len(MyString$)
InputString$=MyString$
success = -1
Else
success =0
EndIf
ProcedureReturn success
EndProcedure
ProcedureDLL.s StringChangerS (InputString$)
;Does not work - triggers error 16 in ms-access 2010 (Expression too Complex) which means that access was expecting an expression that would evaluate to a number rather than being presented with a string.
success.d
MessageRequester( "test",InputString$)
MyString$ = "Hello to you too"
If Len(InputString$) > Len(MyString$)
InputString$=MyString$
EndIf
ProcedureReturn MyString$
EndProcedure
ProcedureDLL.d StringChangerR (*Ptr)
;Does not work - reads gibberish - problem is likely to be that I am not passing a memory address from ms-access (how does one do this?)
success.d
message.s
Rascii.s
Runicode.s
Rutf8.s
Rascii= PeekS(*Ptr,-1,#PB_Ascii)
Runicode=PeekS(*Ptr,-1,#PB_Unicode)
Rutf8=PeekS(*Ptr,-1,#PB_UTF8)
message="Ascii: "+Rascii+Chr(10)+"Unicode: "+Runicode+Chr(10)+"Utf8: "+Rutf8 ;Figure out which encoding has been used
MessageRequester( "test",message)
MyString$ = "Hello to you too"
If Len(RefString$) > Len(MyString$)
;PokeS(,MyString$)
success = -1
Else
success =0
EndIf
ProcedureReturn success
EndProcedure
===VBA===
Code: Select all
Option Compare Database
Option Explicit
Public Declare Function StringChangerR Lib "D:\Temp\2013\Access\StringChanger.dll" (MyString) As Double
Public Sub ChangeMyString()
Dim success As Integer
Dim MyString As String
MyString = "Hello World" & String$(100, vbNullChar) 'Pad string with null to make it longer than return value.
success = StringChangerR(MyString)
Debug.Print success
Debug.Print MyString
End Sub
I can't get this working. Need help.
Andrew M
- netmaestro
- PureBasic Bullfrog
- Posts: 8451
- Joined: Wed Jul 06, 2005 5:42 am
- Location: Fort Nelson, BC, Canada
Re: Return string from PureBasic DLL function crashes ms-acc
I'm not sure but access might expect a bstr. You can make one out of a string like this:
This converts your string to a bstr and returns a pointer to it. It may help.
Code: Select all
Procedure StringToBStr (string$) ; By Zapman Inspired by Fr34k
Protected Unicode$ = Space(Len(String$)* 2 + 2)
Protected bstr_string.l
PokeS(@Unicode$, String$, -1, #PB_Unicode)
bstr_string = SysAllocString_(@Unicode$)
ProcedureReturn bstr_string
EndProcedure
BERESHEIT
Re: Return string from PureBasic DLL function crashes ms-acc
Thanks netmaestro,
As I have to pass the variable as reference, I should be able to continue using the same variable after pb has altered it. I think the issue is that I don't know how to read the memory address provided my ms-access in pb.
I have to meditate on the code above for a while.
Cheers
As I have to pass the variable as reference, I should be able to continue using the same variable after pb has altered it. I think the issue is that I don't know how to read the memory address provided my ms-access in pb.
I have to meditate on the code above for a while.
Cheers
Re: Return string from PureBasic DLL function crashes ms-acc
I have had success with this code:
MS ACCESS
PB DLL
Give it a try
Best regards
MS ACCESS
Code: Select all
Option Compare Database
Option Explicit
Public Declare Function StringChangerR Lib "test.dll" (ByVal PointerToString As Long) As Integer
Public Sub ChangeMyString()
Dim success As Integer
Dim MyString As String
MyString = "Hello World" & String$(100, vbNullChar) 'Pad string with null to make it longer than return value.
success = StringChangerR(StrPtr(MyString))
Debug.Print success
Debug.Print MyString
End Sub
Code: Select all
EnableExplicit
ProcedureDLL StringChangerR (*Ptr)
;Does not work - reads gibberish - problem is likely to be that I am not passing a memory address from ms-access (how does one do this?)
Protected success,
message.s,
Rascii.s,
Runicode.s,
Rutf8.s
Rascii= PeekS(*Ptr,-1,#PB_Ascii)
Runicode=PeekS(*Ptr,-1,#PB_Unicode)
Rutf8=PeekS(*Ptr,-1,#PB_UTF8)
message="Ascii: "+Rascii+Chr(10)+"Unicode: "+Runicode+Chr(10)+"Utf8: "+Rutf8 ;Figure out which encoding has been used
MessageRequester( "test",message)
; Protected MyString$ = "Hello to you too"
; If Len(RefString$) > Len(MyString$)
; ;PokeS(,MyString$)
; success = -1
; Else
; success =0
; EndIf
ProcedureReturn success
EndProcedure
Best regards
Re: Return string from PureBasic DLL function crashes ms-acc
Thanks acreis,
I will give it a go. The StrPtr function is not listed in the ms-access developer reference so no one would find it from that starting point.
On another matter there is another problem with using dll's in ms-access and that is that the path to the dll is hardwritten into the declare statement This took me a while to solve as you cannot replace the path to the dll with a variable. The way to tell ms-access where to find the variable is to change the current directory to the directory with the dll. In my case the drive letter may be different to what it was before so I will have to change the drive letter too. To declare a function in ms-access with a relative path to a dll do the following. It assumes that the dll is in a lib directory which is located in the same folder as the ms-access project.
All the validation and error handling code has been removed for clarity. It is odd but having been working within the confines of ms-access for 20 years, I am still getting to grips with this working with files and directories stuff. I can imagine that scores of other people get stuck with this issue as it is very hard to find the answer on the net. This solutions should also work for ms-Excel. Tested in ms-access 2010.
I will give it a go. The StrPtr function is not listed in the ms-access developer reference so no one would find it from that starting point.
On another matter there is another problem with using dll's in ms-access and that is that the path to the dll is hardwritten into the declare statement
Code: Select all
e.g. Public Declare Function StringChangerR Lib "D:\Temp\2013\Access\StringChanger.dll" (MyString) As Double
Code: Select all
===VBA===
'Set the dll subdirectory
mAppDrive = Left(Application.CurrentProject.Path,1) 'Get the drive letter for the drive which hosts the ms-access project
ChDrive mAppDrive 'Change the current drive
mLibDrive = Application.CurrentProject.Pat & "\Lib" 'Work out where the lib directory should be (and add some code to test that it exists)
ChDir mLibDrive 'Change the directory
Debug.Print CurDir 'Confirm the change
===End VBA===