Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

Unhandled error when exiting an DLL which grabs data from a database and store data into an array of structure

Posted on 2004-09-28
8
1,543 Views
Last Modified: 2008-01-09
Hi,

Here's what I did.
I declared a structure for holding data:

#define LEN_DATA 100

struct DB_DATA
{
      char m_Username[LEN_DATA];
      char m_Password[LEN_DATA];
      char m_Submit[LEN_DATA];
};

DB_DATA* p_DBData = new DB_DATA;

Then I have 2 DLL functions for constructing and destroying the array:

BOOL EXPORTED_DLL_FUNCTION ConstructUserArray()
{

(codes ommited for database connection.. )

      SDWORD cb;
      char szUsername[LEN_DATA];
      char szPassword[LEN_DATA];
      char szSubmit[LEN_DATA];

      SQLBindCol(h_stmt, 1, SQL_C_CHAR, szUsername, LEN_DATA, &cb);
      SQLBindCol(h_stmt, 2, SQL_C_CHAR, szPassword, LEN_DATA, &cb);
      SQLBindCol(h_stmt, 3, SQL_C_CHAR, szSubmit, LEN_DATA, &cb);

      rc = SQLFetch(h_stmt);

      m_NumRecord = 0;

      while (SQL_SUCCESS == rc)
      {
            strcpy(p_DBData[m_NumRecord].m_Username, szUsername);
            strcpy(p_DBData[m_NumRecord].m_Password, szPassword);
            strcpy(p_DBData[m_NumRecord].m_Submit, szSubmit);
            m_NumRecord++;

            rc = SQLFetch(h_stmt);
      }

(codes ommited for database disconnection.. )
}

BOOL EXPORTED_DLL_FUNCTION DestroyUserArray()
{
      for (int i=0; i<sizeof(p_DBData); i++){
            p_DBData[i].m_Username[0] = 0;
            p_DBData[i].m_Password[0] = 0;
            p_DBData[i].m_Submit[0] = 0;
      }
      return true;
}

The error was generated when I was exiting the DLL.. here's what I saw from the Call Stack:

>      mfc71d.dll!CThreadSlotData::GetThreadValue(int nSlot=2012648534)  Line 269      C++

with the code:
inline void* CThreadSlotData::GetThreadValue(int nSlot)
{
      EnterCriticalSection(&m_sect);
      ASSERT(nSlot != 0 && nSlot < m_nMax);
      ASSERT(m_pSlotData != NULL);
      ASSERT(m_pSlotData[nSlot].dwFlags & SLOT_USED);
      ASSERT(m_tlsIndex != (DWORD)-1);
      if( nSlot <= 0 || nSlot >= m_nMax ) // check for retail builds.
      {
            LeaveCriticalSection(&m_sect);
            return NULL;
      }

      CThreadData* pData = (CThreadData*)TlsGetValue(m_tlsIndex);
      if (pData == NULL || nSlot >= pData->nCount)
      {
            LeaveCriticalSection(&m_sect);
            return NULL;
      }
      void* pRetVal = pData->pData[nSlot];
      LeaveCriticalSection(&m_sect);
      return pRetVal;      <------------------------------------------- Line 269
}

I tried to free the variables szUsername, szPassword, szSubmit right after the while loop but then it generates the error at the end of the free() function..

Any help is greatly appreciated..

Thanks a lot.
0
Comment
Question by:ewong_111
  • 4
  • 3
8 Comments
 
LVL 16

Expert Comment

by:nonubik
ID: 12172421
>I tried to free the variables szUsername, szPassword, szSubmit right after the while loop but then it generates the error at the end of the free() function..

There is no need for that, they are staticaly allocated, so you don't need to free them.

As for your problem, try to pass the void * as parameter, not to return it:

inline void CThreadSlotData::GetThreadValue(int nSlot, void *pRetVal)
{
...
   pRetVal = pData->pData[nSlot];
    LeaveCriticalSection(&m_sect);

}
0
 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
ID: 12172483
>>mfc71d.dll!CThreadSlotData::GetThreadValue(int nSlot=2012648534)

Isn't 2012648534 a quite huge value? BTW, when exactly is that function being called? The TLS slot might be gone once the thread detaches.

0
 
LVL 2

Author Comment

by:ewong_111
ID: 12172561
nonubik,

The point is, the CThreadSlotData::GetThreadValue function is in the mfc71d.dll (I assumed) that I am checking the Call stack and see that it hangs there, not that I wrote the function myself and have a control of what to do with it or what valuable I can pass to it.
As I said, my program used an DLL and it works just fine before I exit it. I used a dialog based program to access the DLL and the error was generated when I click on "Cancel" which is to exit the DLL.

ewong_111
0
Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

 
LVL 2

Author Comment

by:ewong_111
ID: 12172604
jkr,

The DLL has another function which set up a hook for monitoring keystrokes and mouse actions.
I am not sure when the CThreadSlotData::GetThreadValue is called, but I "feel" like it is somewhere when my DLL Client program (dialog based) is terminating the DLL.
In addition, the array of structure is used to compare the keystokes with the values in the database.. not sure if this help..
Thanks a lot.

ewong_111
0
 
LVL 2

Author Comment

by:ewong_111
ID: 12172899
Hi,

I tried to change the functions to virtual functions:

class KeyApp : public CWinApp
{
public:
      KeyApp();

// Overrides
public:
      virtual BOOL InitInstance();
      virtual BOOL ExitInstance();
      virtual BOOL ConstructUserArray();
      virtual BOOL DestroyUserArray();

      DECLARE_MESSAGE_MAP()
};

and called the ConstructUserArray() in InitInstance():

BOOL CKeyApp::InitInstance()
{
      ConstructUserArray();
      AFX_MANAGE_STATE(AfxGetStaticModuleState());
      g_hInstance = AfxGetInstanceHandle();
      return TRUE;
}

and the DestroyUserArrar() in ExitInstance():

int CGCRCoKeyApp::ExitInstance()
{
      ExitHook();
      DestroyUserArray();
      return CWinApp::ExitInstance();
}

and now I get the error code in the free() function:
>      msvcr71.dll!free(void * pBlock=0x003745e8)  Line 103      C

#ifdef _MT
            }
            __finally {
                _munlock(_HEAP_LOCK );
            }
#endif  /* _MT */

            if (pmap == NULL)
                HeapFree(_crtheap, 0, pBlock);
        }
#endif  /* CRTDLL */
        else    //  __active_heap == __SYSTEM_HEAP
#endif  /* _WIN64 */
        {
            HeapFree(_crtheap, 0, pBlock);
        }
} <------------------------------------------------ Line 103

jkr, I think your direction is correct, somehow the TLS slot was gone before the thread detaches.. but what did I do to cause that happen?

Thanks a lot..

ewong_111
0
 
LVL 86

Expert Comment

by:jkr
ID: 12172919
Do you have a 'DllMain()' where you can monitor DLL_THREAD_DETACH? That's the time to discard the slot.
0
 
LVL 2

Author Comment

by:ewong_111
ID: 12172986
jkr,

no, I don't have a DllMain(), but I guess it's time for me to build it.. would you please give me a little hint on what to do to discard the slot in there?
Thank you so much.

ewong_111
0
 
LVL 86

Expert Comment

by:jkr
ID: 12173168
I don't know the class you are using, but it'd be something like

// DllMain() is the entry-point function for this DLL.
BOOL
WINAPI
DllMain ( HINSTANCE, DWORD dwReason, LPVOID lpvReserved) {


    switch ( dwReason) {
 
        // The DLL is loading due to process
        // initialization or a call to LoadLibrary.
 
        case DLL_PROCESS_ATTACH:

            // Allocate a TLS index.
 
            if ( 0xFFFFFFFF == ( dwTlsIndex = TlsAlloc ())) {

                return FALSE;
            }

        // No break: Initialize the index for first thread.
 
        // The attached process creates a new thread.
 
        case DLL_THREAD_ATTACH:
 
            // Initialize the TLS index for this thread.
 
            TlsSetValue ( dwTlsIndex, <some pointer value>);
            break;
 
        // The thread of the attached process terminates.
 
        case DLL_THREAD_DETACH:
 
            TlsSetValue ( dwTlsIndex, NULL);
            break;
 
        // DLL unload due to process termination or FreeLibrary.
 
        case DLL_PROCESS_DETACH:

            TlsFree ( dwTlsIndex);
            break;
 
        default:
            break;
    }
 
    return TRUE;
}
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

808 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question