• C

dll writen in c to be used in vb

I Wrote a dll that has a global variable used by both c programs and vb program. is as follows:
=================================
#define FunctionTypeModifier __stdcall

__declspec(thread) UINT igNumber;

void SetNumber(UINT iNumber)
{
   igNumber = iNumber;
}

void  FunctionTypeModifier vbSetNumber(
     long lNumber)
{
   igNumber = (UINT) lNumber;
}
====================================
c programs calls SetNumber
vb programs calls vbSetNumber

this works ok with c

but with vb i get the following message
Unhandled Exception in [test.exe]; 0xC0000005: Access violation.

vb codes is as follows
===============================
Declare Function vbSetNumber Lib "pUtils.dll" (ByVal iNumber As Integer) As Integer

Call vbSetNumber (455)
===================================
Can anyone tell me what I am doing wrong?

Thanks
thevamAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jkrCommented:
If you're declaring the function in VB to return an integer, you have to return an integer in order not to mess up the stack, e.g.

int FunctionTypeModifier vbSetNumber(
     long lNumber)
{
   igNumber = (UINT) lNumber;

  return ( 0);
}

You should also take care about the data types you're using - the ones in your example are all 4 bytes, but you cannot rely on this in the future. So the 'conforming' soultion would be:

int FunctionTypeModifier vbSetNumber(
     int iNumber)
{
   igNumber = (UINT) iNumber;

  return ( 0);
}
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
jkrCommented:
One other thing - are you using a .def file? If not, you might run into difficulties...

Feel free to ask if you need more information!
0
thevamAuthor Commented:
I still have same error. I need to tell you some more things.

1. I am using .def file
2. I have the c functions in one cpp and the vb functions in other

in vb module i have
 __declspec(thread) extern UINT iNumber;

is it ok.

Thanks

0
Has Powershell sent you back into the Stone Age?

If managing Active Directory using Windows Powershell® is making you feel like you stepped back in time, you are not alone.  For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why.

jkrCommented:
This is strange - have you tried to debug the function call, e.g.

int FunctionTypeModifier vbSetNumber(
     int iNumber)
{
  DebugBreak(); /* will cause the debugger to load */
 
   igNumber = (UINT) iNumber;

  return ( 0);
}
0
thevamAuthor Commented:
the problem is elimiated if
  __declspec(thread) UINT igNumber;

is changed to
     UINT igNumber;

but the problem is it is not thread safe




0
jkrCommented:
Well, it seems that VB has problems with this declaration.

Try to initialize the variable, e.g.


  __declspec(thread) UINT igNumber = 0;
0
jkrCommented:
One other thing: '__declspec(thread' does NOT make the function thread safe, it only ensures that each thread holds its own copy of the variable - is this what you want to do?
0
thevamAuthor Commented:
yes sorry that is what i want. Each thread to have a copy of its own global variable. which is set differently for each thread.

Regards
0
thevamAuthor Commented:
__declspec(thread) UINT igNumber = 0;

this does not work ether
0
jkrCommented:
Well, I suspect that the C runtime isn't initialized correctly when the DLL is loaded from a VB app - did you take a look into 'TlsAlloc()' and friends?
0
viktornetCommented:
thevam, in the DLL (C/C++) code you should define the function as a __stdcall so the parameters are passed in reverse order from what C/C++ is used to... that's what all API functions do, and that's the way VB is trying to call it.

Good Luck!

..-=ViKtOr=-..
0
jkrCommented:
Viktor, it is defined as __stdcall ...
0
thevamAuthor Commented:
#define FunctionTypeModifier __stdcall

is defined in the code already.

Thanks
0
jkrCommented:
Have you tried

DWORD TlsIndex;

BOOL WINAPI DllMain(
    IN HINSTANCE hinstDll,
    IN DWORD fdwReason,
    LPVOID lpvReserved
    )
{

   switch (fdwReason) {

   case DLL_PROCESS_ATTACH:
      // DLL is attaching to the address
      // space of the current process.
      TlsIndex = TlsAlloc();
      break;

   case DLL_PROCESS_ATTACH:
      TlsFree ( TlsIndex);
      break;
      }

int FunctionTypeModifier vbSetNumber(
     int iNumber)
{
   TlsSetValue ( TlsIndex, ( LPVOID) iNumber);

  return ( 0);
}

int FunctionTypeModifier vbGetNumber(
     int iNumber)
{
   return ( ( int) TlsGetValue ( TlsIndex));

}
0
jkrCommented:
BTW: You'll have to go that way, as VB dynamically loads your DLL - quote:

"When you use the compiler directive _ _declspec(thread), the data that you define doesn't go into either the .data or .bss sections. It ends up in the .tls section, which refers to "thread local storage," and is related to the TlsAlloc family of Win32 functions. When dealing with a .tls section, the memory manager sets up the page tables so that whenever a process switches threads, a new set of physical memory pages is mapped to the .tls section's address space. This permits per-thread global variables. In most cases, it is much easier to use this mechanism than to allocate memory on a per-thread basis and store its pointer in a TlsAlloc'ed slot.

There's one unfortunate note that must be added about the .tls section and _ _declspec(thread) variables. In Windows NT and Chicago, this thread local storage mechanism won't work in a DLL if the DLL is loaded dynamically by LoadLibrary. In an EXE or an implicitly loaded DLL, everything works fine. If you can't implicitly link to the DLL, but need per-thread data, you'll have to fall back to using TlsAlloc and TlsGetValue with dynamically allocated memory."

(see http://msdn.microsoft.com/library/techart/msdn_peeringpe.htm )
0
viktornetCommented:
opps... i guess i've missed the declaration (#define)... i apologize..
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C

From novice to tech pro — start learning today.