Link to home
Start Free TrialLog in
Avatar of sopppas
sopppas

asked on

application crash outside Visual Studio

hi,

i've developped an mfc application, which uses 2 external dlls (Xerces and curl) and an activeX control to access the local machine's WMI and produce a XML file with the information.
The application does it's stuff in a timer triggered loop, ie every 30 seconds or so it accesses some info via WMI.

Everything works fine when I run the app inside VS.NET (in both debug and release configs), but when i run the app outside the IDE, it crashes after the first loop (sometimes it goes for a few loops, sometimes just one).

All this in windows xp sp1.

All the memory leak detectors i've tried report no leaks.

When I JIT debug, I see that the crash happens on code that has worked on previous iterations, sometimes on the Xerces stuff, other times on my registry accessing functions (RegQueryValueEx, namely). I get a "Memory could not be read[/written] sometimes" error. I have looked in to some dynamic condition that would cause the error, but i can't get past the fact that all the iterations are exactly alike (same information retrieved over and over again) and the code works inside VS.NET (both configs).

All this happens only from the second iteration of the program onward. To my best knowledge, the registry related system calls are made as seen on the msdn sample code. xerces stuff is also very much like the samples (including cleanup stuff).

help much appreciated. thanks!

sopppas
Avatar of jkr
jkr
Flag of Germany image

>>Everything works fine when I run the app inside VS.NET

As you haven't posted any code: Check for uninitialized variables, especially pointers. The behaviour you described is typical for such small mistakes.
Avatar of AlexFM
AlexFM

The difference in running application from VS and out of it is current directory. Maybe this can be a reason?
Avatar of sopppas

ASKER

hi,

AlexFM I've tried running the program inside the Debug|Release directory and in the project dir. No luck!

I'm gonna provide you with some code, then:

- the whole program is a systray application which, from time to time, iterates do find system info. This is done with the following loop:

void CEasyAppDlg::OnTimer (UINT TimerVal)
{
      KillTimer(timerId);

#ifdef _DEBUG
      CMemoryState oldMemState, newMemState, diffMemState;
      oldMemState.Checkpoint();
#endif
      
      CEasyApp::XMLCreate();
      

#ifdef _DEBUG
      newMemState.Checkpoint();
      if( diffMemState.Difference( oldMemState, newMemState ) )
    {
        TRACE( "Memory leaked!\n" );
            oldMemState.DumpStatistics();
    }
#endif

      timerId = SetTimer(IDT_TIMER_0, 1000, NULL); // 30 segundos
}

this function is also called when the program is first started, ie inside the OnInitDialog. As previously stated, no memory leaks are reported by CMemoryState.

- anyways, CEasyApp::XMLCreate is the core function of the program: it makes A LOT of wmi queries, a few registry ones, and uses xerces to create a XML file with the collected system info. These queries are made from within an ocx active X controller. The following are examples of how I'm doing this
 
      
      // inside XMLCREATE
      CString str;
      str = CagenteActXApp::getDomainAndName(); // the getDomainAndName function is in the ocx

      machineElem->setAttribute(X("id"), X(str)); // these are Xerces lib functions.
      ////////////////////////////


      // this function is defined in the ocx
      CString CagenteActXApp::getDomainAndName() {

      HRESULT hr;

      // Get list of objects
      CComPtr<IEnumWbemClassObject> spEnumInst;
      CComBSTR bstrQuery("SELECT * FROM Win32_ComputerSystem");

      hr = spServices->ExecQuery(CComBSTR(_T("WQL")), bstrQuery,
                  WBEM_FLAG_BIDIRECTIONAL, NULL, &spEnumInst); // some crashes occur in this line on the 2nd or 3rd iteration

      CComVariant varName, domain;
      bool bFinished = false;
      while (!bFinished)
      {
            ULONG uNumOfInstances = 0;
            CComPtr<IWbemClassObject> spInstance;
            HRESULT hrNext = spEnumInst->Next(10000, 1, &spInstance,
                  &uNumOfInstances);
            
            if (hrNext == WBEM_S_FALSE || uNumOfInstances == 0)
                  bFinished = true;
            else
            {
                  // Get properties from the object
                  hr = spInstance->Get(CComBSTR(_T("Name")), 0, &varName, 0, 0);
                  hr = spInstance->Get(CComBSTR(_T("Domain")), 0, &domain, 0, 0);
      
            }
      }

      BSTR bstr = V_BSTR(&domain);
      BSTR bstr2 = V_BSTR(&varName);
      
      CString cs(bstr);
      cs += "\\";
      CString cs2(bstr2);
      cs += cs2;
      
      VariantClear(&varName);
      VariantClear(&domain);

      return cs;  // returns something like WORKGROUP\MYCOMPUTER
      }
      /////////////////

      // again in XMLCreate;
      list<CString> propVal2;
      CagenteActXApp::getSoftwareSet(&propVal2); // this retrieves all the installed programs
      //////////////////////

      void CagenteActXApp::getSoftwareSet(std::list<CString> *res) {


      CHAR    swName[sizeof( DWORD ) * 1024] = ""; // Buffer for class name.


      HKEY hKey;
      HKEY hKeyRoot;

      hKeyRoot = HKEY_LOCAL_MACHINE;

      HRESULT retCode;

      retCode = RegOpenKeyEx (hKeyRoot,
                            "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
                            0,
                            KEY_ALL_ACCESS,
                            &hKey);

      list<char *> keys;
      HRESULT hr = 0;
      int j = 0;
      while(hr != ERROR_NO_MORE_ITEMS) {
            DWORD dwSize = sizeof( DWORD ) * 1024;
            swName[0] = '\0';
            rucucu = RegEnumKeyEx(
                                    hKey,         // handle of key to enumerate
                                    j,            // index of subkey to enumerate
                                    swName,         // address of buffer for subkey name
                                    &dwSize,         // address for size of subkey buffer
                                    NULL,         // reserved
                                    NULL,         // address of buffer for class string
                                    0,            // address for size of class buffer
                                    NULL          // address for time key last written to
                                    );
            keys.push_back(strdup(swName));
            j++;
      }

      while(!keys.empty()) {
            TCHAR skey[sizeof(DWORD)*1024];
            DWORD dwSize = sizeof( DWORD ) * 1024;
            strcpy(skey, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\0");
            strcat(skey, "\\");
            strcat(skey, keys.front());
            strcat(skey, "\0");
            delete keys.front();
            keys.pop_front();
            HKEY hKey2;

            retCode = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
                            skey,
                            0,
                            KEY_ALL_ACCESS,
                            &hKey2);

            skey[0] = '\0';

            retCode = RegQueryValueEx(hKey2, "DisplayName", 0, NULL, NULL, &dwSize ); // it's been known to crash here
            retCode = RegQueryValueEx(hKey2, "DisplayName", 0, NULL, (BYTE *)&skey, &dwSize );
            if(skey[0] == '\0') {
                  dwSize = sizeof( DWORD ) * 1024;
                  retCode = RegQueryValueEx(hKey2, "Display Name", 0, NULL, NULL, &dwSize );
                  retCode = RegQueryValueEx(hKey2, "Display Name", 0, NULL, (BYTE *)&skey, &dwSize );
            }
            if(skey[0] == '\0') {
                  dwSize = sizeof( DWORD ) * 1024;
                  retCode = RegQueryValueEx(hKey2, "QuietDisplayName", 0, NULL, NULL, &dwSize );
                  retCode = RegQueryValueEx(hKey2, "QuietDisplayName", 0, NULL, (BYTE *)&skey, &dwSize );
            }

            strcat(skey, "\0");
            if(skey[0] != '\0'){
                  res->push_back(skey);
            }
            
            RegCloseKey (hKey2);

      }

      RegCloseKey (hKey);
      }
      
I think this illustrates how must of it is being done...
Thanks for the suggestions so far.
s
A couple of bits which look dubious are

     HRESULT hr = 0;
     int j = 0;
     while(hr != ERROR_NO_MORE_ITEMS) {
          DWORD dwSize = sizeof( DWORD ) * 1024;
          swName[0] = '\0';
          rucucu = RegEnumKeyEx(
                              hKey,         // handle of key to enumerate
                              j,            // index of subkey to enumerate
                              swName,         // address of buffer for subkey name
                              &dwSize,         // address for size of subkey buffer
                              NULL,         // reserved
                              NULL,         // address of buffer for class string
                              0,            // address for size of class buffer
                              NULL          // address for time key last written to
                              );
          keys.push_back(strdup(swName));
          j++;
     }

the swName is pushed onto list even if RegEnumKeyEx failed.
also hr does not ppear to be changed, as rucucu is the return value, also what about errors other than NO_MORE _ITEMS .

also on the

retCode = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
                            skey,
                            0,
                            KEY_ALL_ACCESS,
                            &hKey2);

the retVal is  not checked. Which could lead to problems with the RegQueryValueEx
Avatar of sopppas

ASKER

Hi everyone,

I've got it! Don't really know what was wrong, but it seems to be working now.

this code doen't work:

        CComVariant varName;
      bool bFinished = false;
      while (!bFinished)
      {
            ULONG uNumOfInstances = 0;
            CComPtr<IWbemClassObject> spInstance = 0;
            HRESULT hrNext = spEnumInst->Next(10000, 1, &spInstance,
                  &uNumOfInstances);
      
            if (hrNext == WBEM_S_FALSE || uNumOfInstances == 0) // jit debug often indicated a crash right here
                  bFinished = true;
            else
            {
 (...)

and this does:

bool bFinished = false;
      while (!bFinished)
      {
            // Get the instance
            ULONG uNumOfInstances = 0;
            CComPtr<IWbemClassObject> spInstance;
            HRESULT hrNext = spEnumInst->Next(10000, 1, &spInstance,
            &uNumOfInstances);
 
            if (hrNext == WBEM_S_FALSE)
                  bFinished = true;
            else if (hrNext == WBEM_S_NO_ERROR)
            {

I can't really tell where exactly the error is, but maybe the result is sometimes an error code other than WBEM_S_FALSE, causing the problem.
Anyway, thanks  bearcrsw for the tips (I'm gonna use them anyway), and thanks to everyone else who took the time to respond to this cry for help!

s
ASKER CERTIFIED SOLUTION
Avatar of Computer101
Computer101
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial