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
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
The difference in running application from VS and out of it is current directory. Maybe this can be a reason?
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::getDomainA ndName(); // 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::getDomainA ndName() {
HRESULT hr;
// Get list of objects
CComPtr<IEnumWbemClassObje ct> spEnumInst;
CComBSTR bstrQuery("SELECT * FROM Win32_ComputerSystem");
hr = spServices->ExecQuery(CCom BSTR(_T("W QL")), 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::getSoftwar eSet(&prop Val2); // this retrieves all the installed programs
//////////////////////
void CagenteActXApp::getSoftwar eSet(std:: list<CStri ng> *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\\Wind ows\\Curre ntVersion\ \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(swNa me));
j++;
}
while(!keys.empty()) {
TCHAR skey[sizeof(DWORD)*1024];
DWORD dwSize = sizeof( DWORD ) * 1024;
strcpy(skey, "SOFTWARE\\Microsoft\\Wind ows\\Curre ntVersion\ \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
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::getDomainA
machineElem->setAttribute(
//////////////////////////
// this function is defined in the ocx
CString CagenteActXApp::getDomainA
HRESULT hr;
// Get list of objects
CComPtr<IEnumWbemClassObje
CComBSTR bstrQuery("SELECT * FROM Win32_ComputerSystem");
hr = spServices->ExecQuery(CCom
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(_
hr = spInstance->Get(CComBSTR(_
}
}
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::getSoftwar
//////////////////////
void CagenteActXApp::getSoftwar
CHAR swName[sizeof( DWORD ) * 1024] = ""; // Buffer for class name.
HKEY hKey;
HKEY hKeyRoot;
hKeyRoot = HKEY_LOCAL_MACHINE;
HRESULT retCode;
retCode = RegOpenKeyEx (hKeyRoot,
"SOFTWARE\\Microsoft\\Wind
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(swNa
j++;
}
while(!keys.empty()) {
TCHAR skey[sizeof(DWORD)*1024];
DWORD dwSize = sizeof( DWORD ) * 1024;
strcpy(skey, "SOFTWARE\\Microsoft\\Wind
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(swNa me));
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
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(swNa
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
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
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
As you haven't posted any code: Check for uninitialized variables, especially pointers. The behaviour you described is typical for such small mistakes.