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,552 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
[X]
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
  • 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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

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

Suggested Solutions

Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

739 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