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,539 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
PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

 
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

VMware Disaster Recovery and Data Protection

In this expert guide, you’ll learn about the components of a Modern Data Center. You will use cases for the value-added capabilities of Veeam®, including combining backup and replication for VMware disaster recovery and using replication for data center migration.

Question has a verified solution.

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

Suggested Solutions

Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their wa…
Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
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.

823 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