UtterAccess.com
X   Site Message
(Message will auto close in 2 seconds)

Welcome to UtterAccess! Please ( Login   or   Register )

Custom Search
 
   Reply to this topicStart new topic
> Dll With Callback Problem, Access 2010    
 
   
nonlinearly
post May 28 2019, 03:10 AM
Post#1



Posts: 7
Joined: 15-February 11



I have made a simple dll with C for use in an Ms Access vba project. The dll makes a new thread and makes use of a vba callback function inside the thread's code. According to MS documentation the vba callback function has to be in a vba module and not in a form's code. Inside the callback function I set a form's filter property. But because of this the Access crashes when the execution it arrives there!!! Why? Other references to form's components have no problem (for example when I set the value of the form's textbox)
The mysterious is that I found the problem exists only when the vba Callback Sub is called from the Thread function (ThreadFunc). If it is called from within dll main thread then form's filter is set ok without crash (!!!)

Thanks

The C dll code compiled with VS 2017:
CODE
#include <windows.h>
#include <stdlib.h>
#include <tchar.h>

typedef void(__stdcall * CallbackFunction)();

DWORD __stdcall ThreadFunc(CallbackFunction Callback) {
    Callback();
    return 0;
}

__declspec(dllexport) void __stdcall message(CallbackFunction Callback) {
     // Array to store thread handles
    HANDLE Array_Of_Thread_Handles[1];
    Array_Of_Thread_Handles[0] = CreateThread(NULL, 0, ThreadFunc, Callback, 0, NULL);
}
And here is the code that call the dll function "message" from within vba
CODE
Private Sub Form_Load()
    Call message(AddressOf Callback)
End Sub
The vba Declaration of dll
CODE
Public Declare Sub message Lib "test.dll" Alias "_message@4" (ByVal Callback As Long)
The vba callback subroutine (resides on a Module according to MS documentation)
CODE
Public Sub Callback()
    On Error Resume Next
    Forms("MyForm").txtTest="test" 'this line executed well and the string "test" appears ok in the form.
    Forms("MyForm").Filter="" 'in this line Access crashes out
    Forms("MyForm").FilterOn=True
End Sub

This post has been edited by nonlinearly: May 28 2019, 03:32 AM
Go to the top of the page
 
daolix
post May 28 2019, 03:54 AM
Post#2



Posts: 9
Joined: 29-September 16



When you create a thread with your dll, it runs parallel to the access thread. These threads, if they access the same data or data structures, must be secured by appropriate methods (mutex/semaphore/locks/etc.) so that the different threads do not access the same data structure at the same time and thus create an inconsistent state of the data.
Go to the top of the page
 
nonlinearly
post May 28 2019, 04:09 AM
Post#3



Posts: 7
Joined: 15-February 11



Thanks for your reply... I know that but your answer is very generic and it doesn't respond to the specific problem. When the filter is set from the thread's dll the Access thread doesn't make anything to change the same time the filter property of the form. But even if this was true the only problem would be that we can not predict what the value of the filter would be and not to crashed out all the application
Besides, at the same time, the value of any textbox inside form can change as I mentioned. Why can we change the value of the form's textbox but not the Filter property of the form? The same for any other property of the form for example MyForm.RecordSource
This post has been edited by nonlinearly: May 28 2019, 04:12 AM
Go to the top of the page
 
jleach
post May 28 2019, 07:29 AM
Post#4


UtterAccess Editor
Posts: 10,019
Joined: 7-December 09
From: St Augustine, FL


It could be that changing the filter causes the form to requery, which may have adverse effect because of the owning thread.

Just curious, why are you trying to do this? What do you gain from it? While Access itself is multithreaded, the programming model that we have to work with is not, and because of that we really don't have any mechanics for thread safety.

--------------------
Go to the top of the page
 
PhilS
post May 28 2019, 07:58 AM
Post#5



Posts: 578
Joined: 26-May 15
From: The middle of Germany


QUOTE
The dll makes a new thread and makes use of a vba callback function inside the thread's code. According to MS documentation the vba callback function has to be in a vba module and not in a form's code. Inside the callback function I set a form's filter property. But because of this the Access crashes when the execution it arrives there!!! Why? Other references to form's components have no problem (for example when I set the value of the form's textbox)

Accessing UI-Elements owned by the main thread of an application from other "user-created" threads is always problematic and risky. Not only in Access/VBA, but in most (all?) other languages as well.
I guess you were just lucky that setting the text box value did not cause problems, yet. Changing the filter of a form has huge implications regarding (re)querying the displayed data and all sorts of other UI dependencies on that.

Can you try to sync the "event" back to the main thread in your DLL and invoke the callback on the main thread?


Generally, thinking beyond the Access/UI problem at hand, having multiple threads directly writing to a shared object (the form) without any synchronization logic in place (as @daolix mentioned already) is a sure-fire method of creating all sorts of hard-to-debug concurrency issues.
This post has been edited by PhilS: May 28 2019, 07:58 AM

--------------------
Go to the top of the page
 
nonlinearly
post May 29 2019, 07:09 AM
Post#6



Posts: 7
Joined: 15-February 11



QUOTE
Can you try to sync the "event" back to the main thread in your DLL and invoke the callback on the main thread?


How can I do that?
Go to the top of the page
 
PhilS
post May 29 2019, 07:37 AM
Post#7



Posts: 578
Joined: 26-May 15
From: The middle of Germany


QUOTE
QUOTE
Can you try to sync the "event" back to the main thread in your DLL and invoke the callback on the main thread?

How can I do that?

I cannot answer this for C/C++.

Within the .Net-World one approach would be to write a delegate that implements the ISynchronizeInvoke interface and then invoke that delegate.

There should be an alternative approach which works with C/C++, but that is not my domain of expertise.

--------------------
Go to the top of the page
 
nonlinearly
post Jun 3 2019, 04:47 AM
Post#8



Posts: 7
Joined: 15-February 11



Thanks but I don't know how to do this in C.
The code of main thread is the code of the vba that calls the dll "message" function (message(addressOf Callback)) and the code of the dll "message" function that create the dll because they are not run asynchronously.
The problem is that after the dll "message" function creates the thread then it keeps going to run until end.
So what C code will the thread return to when it's needed since the main thread C "message" code anyway will be over?
I think that the solution is to make a COM component that it is more robust than a simple (and unmanged) dll because as I know COM is more suitable for managing communication between two dissimilar applications. The problem is that I don't know how to make a COM component

Thanks
This post has been edited by nonlinearly: Jun 3 2019, 04:48 AM
Go to the top of the page
 
jleach
post Jun 3 2019, 05:41 AM
Post#9


UtterAccess Editor
Posts: 10,019
Joined: 7-December 09
From: St Augustine, FL


Just curious, why do you need this to come back to VBA from a callback? If you want the C code to "run to the end", why not just return the data from the function you call instead of having it pumped as a message through the callback?

Maybe if we understood what you're ultimately trying to accomplish, we can think of an easier way?

--------------------
Go to the top of the page
 
nonlinearly
post Jun 4 2019, 07:01 AM
Post#10



Posts: 7
Joined: 15-February 11



Hi jleach, thanks for your reply...
1. What do you mean about callback return to vba? We are in an Access Forum after all! callback function IS vba function anyway so vba code will be executed!! If I was using a return function (callbaack) that resides on C dll code how would my Access application be updated?
2. It's not me who wants the C "message" function code to run to the end. It's just that when you create a thread. The remaining code after creating the thread will continue unless you use wait functions (like WaitForMultipleObjects or WaitForSingleObject) to wait until the thread to finish. But then because dll "message" function belongs to main Access thread the Access will hang until thread's code is over. But my original thread is run infinitely (wait continuously for a file's change) so Access UI will be freeze for ever.
Thanks
This post has been edited by nonlinearly: Jun 4 2019, 07:03 AM
Go to the top of the page
 
jleach
post Jun 4 2019, 08:05 AM
Post#11


UtterAccess Editor
Posts: 10,019
Joined: 7-December 09
From: St Augustine, FL


Ah, I see (sorry, wasn't sure the context here, but now I get it - wasn't sure why you were using a callback instead of waiting for the C function to complete, but now I understand that you're looking for a filesystem monitor notification, and thus C caller doesn't really "complete").

Not sure the best way about this offhand (not without giving it some further thought, which I don't have time for at the moment). One thing that comes to mind: have you considered implementing a queue and poll? For example, have your C code write a file change notification into a queue (disk, table, or maybe even memory if you can match the safearray structure), then have your Access app poll the queue for changes? This would break the thread issue and can typically be done with a few second's worth of lag if the VBA project doesn't need immediate notification.

It's a bit off-path of your current approach, but could prove much more stable in the longrun.

Another idea: have you consider something like this: https://dymeng.com/async-processing-in-access/ Perhaps you could use the technique to poll your filesystem from the secondary app without necessarily having to go through C for it. Just a thought.

hth

--------------------
Go to the top of the page
 
nonlinearly
post Jun 4 2019, 09:48 AM
Post#12



Posts: 7
Joined: 15-February 11



Thanks for your ideas but I need a realtime solution. No polling.
Go to the top of the page
 
PhilS
post Jun 11 2019, 10:51 AM
Post#13



Posts: 578
Joined: 26-May 15
From: The middle of Germany


The topic of multithreading with VBA was on my list for quite a while.This thread finally pushed me to record a video on that topic. - It's not really a solution to the issues raised here, but it covers several sidelines touched by this this thread.
So, I think it is justified to post a link here: Multithreading with VBA?

--------------------
Go to the top of the page
 


Custom Search


RSSSearch   Top   Lo-Fi    18th July 2019 - 04:38 AM