EXE running on server - vb6

Exe made in vb6 will hang if its continously run on server? This exe has winsock component which is used to received data from biometric readers and saved in sql server 2005. Actually this shows real time list for acceess made on biometric readers means in this exe we have used datagrid component which display saved records in sql. How to refresh this exe and data.?

Well, if you're displaying a GUI then I'd say technically you are not running on a server. But I still don't see how doing this will make the program "hang."
There are some things to be careful of when it comes to VB6 memory leaks. One thing to be sure to do is make sure you use the SP6 version of the VB6 runtime and "extended runtime" (the set of controls that ship with VB6). The other is probably to go over the code and look for circular object references that may result in accumulated orphaned objects over time. There were also a few obscure ADO memory leaks that never got fixed until MDAC 2.7, but most of those don't impact a VB6 program.
I suspect there are other causes of hangs, but most of those are probably faulty logic such as loops containing DoEvents calls. Using Winsock for TCP without a full understanding could also produce programs that seem to work at times and then hang awaiting something that nevers happens other times. Remember, on every DataArrival event you can count on at most one byte of data - you need to write your own stream assembly and message parsing logic. One SendData call at a sender does not equal one GetData call at the receiver!
Sent: abc
Received: a
bc
If the program calls GetData until it gets "abc" it will never see it!

Related

Diagnosing Win32 RegisterClass leak

We are trying to troubleshoot a nasty problem on a production server where the server will start misbehaving after running for awhile.
Diagnostics have led us to believe there may be a bug in a DLL that is used by one of the processes running on this server that is resulting in a global atom leak. The assumed vector is a process that is calling RegisterClass without a corresponding UnregisterClass (and the class name is using a random number as part of the name, so it's a different class name each time the process starts).
This article provided some information: https://blogs.msdn.microsoft.com/ntdebugging/2012/01/31/identifying-global-atom-table-leaks/
But we are reluctant to attempt kernel mode debugging on a production server, so we have tried installing windbg and using the !gatom command to list atoms for a given session.
I use windbg to attach to a process in one of the sessions (these processes are running as Windows Services if that matters), then invoke the !gatom command. The returned atom list doesn't have any window classes in it.
Then I read this: https://blogs.msdn.microsoft.com/oldnewthing/20150429-00/?p=44984
and it sounds like there is a separate atom table for windows classes. And no way to query it. I was hoping that we'd be able to actually see how many windows class atoms have been registered, and see if that list gets bigger over time, indicating a leak.
The documentation on !gatom is sparse, and I'm hoping I can get some expert confirmation or recommendations on how to proceed.
Does anyone have any ideas on how we can get at the list of registered Windows classes on a production server?
More detail about what happens when the server starts to misbehave:
We run many instances (>50) of the same application as separately registered services running from isolated executables and DLLs - so each of those 50 instances has their own private executables and DLLs.
During their normal run, the processes unload and reload a DLL (about every hour). There is a windows class used that's part of a "session handle" used by the DLL (the session handle is part of the registered windows class name), and that session handle is unique each time the DLL is loaded. So every hour, there is an additional Window class registration, made by a DLL (our service stays running).
After some period of time, the system will get into a state where further attempts to load the DLL in question fail. This may happen for one of the services, then gradually over time, other services will start to have the same problem.
When this happens, restarting the service does not fix the problem. The only way that we've found to get things running properly again is to reboot the server.
We are monitoring memory commit load, and we are well within the virtual memory of the server. We are even within the physical memory size.
I just did a code review the vendor of the DLL, and it looks like they are not actually calling RegisterClass from the DLL itself (they only make one RegisterClass call from the DLL, and it's a static string - not a different class name for each session). The DLL launches an EXE, and that EXE is the one that registers the session specific class name. Their EXE does call UnregisterClass (and even if it didn't, the EXE is terminated when we unload their DLL, so it seems that this may not be what is going on).
I am now out of bullets on this one. The behavior seems like some sort of resource leak or pool exhaustion. The next time this happens, I will try connecting to the failing process with windbg and see what the application atom pool looks like - but I'm not hopeful that is going to shed any light.
Update: The excellent AtomTableMonitor tool has narrowed the problem to rogue RegisterWindowMessage. I'm going to ask a more specific question focused on this exact issue: Diagnosing RegisterWindowsMessage leak
You may try using this standalone global atom monitor
The application appears to have capabilities to monitor atoms in services
that run in a different session
btw if you have narrowed it to RegisterWindowMessage
then spy++ can log the Registered messages system wide along with thread and process
spy++ (i am using it from vs2015 community)
ctrl+m select all windows in system
in the messages tab clear all and select registered
and start logging
you can also save the log (it is plain text in-spite of strange extension )
powershell -c "gc spy++.sxl -Tail 3"
<000152> 001F01A4 P message:0xC1B2 [Registered:"nsAppShell:EventID"] wParam:00000000 lParam:06EDFCE0 time:4:2
7:49.584 point:(408, 221)
<000153> 001F01A4 P message:0xC1B2 [Registered:"nsAppShell:EventID"] wParam:00000000 lParam:06EDFCE0 time:4:2
7:49.600 point:(408, 221)
<000154> 001F01A4 P message:0xC1B2 [Registered:"nsAppShell:EventID"] wParam:00000000 lParam:06EDFCE0 time:4:2
7:49.600 point:(408, 221)

Debugging Visual Basic Runtime Error 5

I have a Visual Basic 4 32 bit application which results in a
Run-time error '5':
Invalid procedure call
I start WinDbg and do
sxe *
to break on all exceptions. However, it displays the message without breaking into the debugger before.
If I break at the time of the message, the callstack is not very useful. Is there a trick to break-in on Visual Basic 4 applications at the time the problem occurs?
Problem FAQ:
Can you run it in the IDE?
Yes I can and I can probably fix the bug when I do that. However, I'd like to get some more information at the time the end user runs the application so that I don't need to be able to reproduce it.
What do you want to do in case you find the cause of the error?
Well, it depends on the type of the error. Maybe I can fix it, maybe I can't. Usually I get some very helpful information out of WinDbg.
When does the error occur?
It occurs reproducibly when the user presses a close button on a form.
What does the application do?
Oh, that's a good question. I don't exactly know. It uses RS232 communication but it's not yet involved.
Do you know anything about the data the user can enter?
I almost know nothing about it. In this particular case, it's not necessary to enter data.
The error is from the VB virtual machine not from an API.
I can't see how WinDbg would be useful on VB4 which is interpreted and is in P-Code.
Visual Basic run-time error 5 Indicates one of the following:
An invalid collection or property name was entered.
An out parameter was NULL.
The value is not one of the supported values or falls outside the supported range.
The property is read-only.
The property cannot be changed after the object is created.
An invalid index was entered.
And in case it's an API call VB uses LoadLibrary and GetProcAddress.
Some controls have lost default values over time and this can cause the first.
The third can happen if modern technology exceeds the program's expection, e.g. disk space.
Also see (sorry no links, they are on my hard disk)
Q131007 HOWTO: Use Windows NT WinDbg.exe with Visual Basic (it's for NT 3.5)
Q166275 HOWTO: Debug a Native Code Visual Basic Component in VC++ (talks about what you can see in VB in a debugger)
VB4 can't make symbols
As the error occurs when the users presses the close button i assume there is a (very tight) loop running which doesn't receive the expected data (probably a nullstring)
I expect that that loop is continuously reading data from the RS232 device and the RS232 is on the form which is being closed, even though it is not involved the connection might already be open and polling
What you should do is exit that loop and close the connection with the RS232 device before closing the form. You might be able to do that in the Form_Unload() event, but it might also have to take place before that, so you might have to do it in the code of the close button ... make sure though that the user won't be using the X to close the form though
Personally i would run the program from within the IDE, this will point you to the errornous part of the code directly and gives you the opportunity to watch the contents of the variables involved and control states ... that is much faster than taking a guess based on the data of WinDbg

Windows 7 and VB6: Event Error ID 1000

I have a completely random error popping up on a particular piece of software out in the field. The application is a game written in VB6 and is running on Windows 7 64-bit. Every once in a while, the app crashes, with a generic "program.exe has stopped responding" message box. This game can run fine for days on end until this message appears, or within a matter of hours. No exception is being thrown.
We run this app in Windows 2000 compatibility mode (this was its original OS), with visual themes disabled, and as an administrator. The app itself is purposely simple in terms of using external components and API calls.
References:
Visual Basic for Applications
Visual Basic runtime objects and procedures
Visual Basic objects and procedures
OLE Automation
Microsoft DAO 3.51 Object Library
Microsoft Data Formatting Object Library
Components:
Microsoft Comm Control 6.0
Microsoft Windows Common Controls 6.0 (SP6)
Resizer XT
As you can see, these are pretty straightforward, Microsoft-standard tools, for the most part. The database components exist to interact with an Access database used for bookkeeping, and the Resizer XT was inserted to move this game more easily from its original 800x600 resolution to 1920x1080.
There is no networking enabled on the kiosks; no network drivers, and hence no connections to remote databases. Everything is encapsulated in a single box.
In the Windows Application event log, when this happens, there is an Event ID 1000 faulting a seemingly random module -- so far, either ntdll.dll or lpk.dll. In terms of API calls, I don't see any from ntdll.dll. We are using kernel32, user32, and winmm, for various file system and sound functions. I can't reproduce as it is completely random, so I don't even know where to start troubleshooting. Any ideas?
EDIT: A little more info. I've tried several different versions of Dependency Walker, at the suggestion of some other developers, and the latest version shows that I am missing IESHIMS.dll and GRPSVC.dll (these two seems to be well-known bugs in Depends.exe), and that I have missing symbols in COMCTRL32.dll and IEFRAME.dll. Any clues there?
The message from the application event log isn't that useful - what you need is a post mortem process dump from your process - so you can see where in your code things started going wrong.
Every time I've seen one of these problems it generally comes down to a bad API parameter rather than something more exotic, this may be caused by bad data coming in, but usually it's a good ol fashioned bug that causes the problem.
As you've probably figured already this isn't going to be easy to debug; ideally you'd have a repeatable failure case to debug, instead of relying on capturing dump files from a remote machine, but until you can make it repeatable remote dumps are the only way forwards.
Dr Watson used to do this, but is no longer shipped, so the alternatives are:
How to use the Userdump.exe tool to create a dump file
Sysinternals ProcDump
Collecting User-Mode dumps
What you need to get is a minidump, these contain the important parts of the process space, excluding standard modules (e.g. Kernel32.dll) - and replacing the dump with a version number.
There are instructions for Automatically Capturing a Dump When a Process Crashes - which uses cdb.exe shipped with the debugging tools, however the crucial item is the registry key \\HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\AeDebug
You can change your code to add better error handling - especially useful if you can narrow down the cause to a few procedures and use the techniques described in Using symbolic debug information to locate a program crash. to directly process the map files.
Once you've got a minidump and the symbol files WinDbg is the tool of choice for digging into these dumps - however it can be a bit of a voyage to discover what the cause is.
The only other thing I'd consider, and this depends on your application structure, is to attempt to capture all input events for replay.
Another option is to find a copy of VMWare 7.1 which has replay debugging and use that as the first step in capturing a reproducible set of steps.
Right click your executable object and let it be WINXP compatible pending
when you discover source of the problem to finally solve it

Delphi App Communicates with Program That Ends Up Crashing Occasionally - Vendor Blames My Delphi App

I've written a Delphi DLL that communicates with a third party program via COM. Some users report that the third party program crashes occasionally. Others using the software in an identical fashion have never experienced a crash. When this crash occurs, the third party program appears to simply become unavailable in my DLL app.
The vendor swears that it is a problem with how the Delphi DLL is coded, although they have not seen the source code and can't tell what what the DLL is doing to cause the crash, but they know it's "something".
Aside from the fact that I believe that the third party program shouldn't be crashing due to some minuscule problem in my DLL, let's assume that there is something in my DLL that needs fixing.
How can I determine how my app might be causing this? Does anyone have experience communicating via COM with a hyper-sensitive program like this? Are there some common things to look for that might be crashing the third party program?
Make the customer happy.
Don't assume it's not your dll, it could be. Even if "Others using the software in an identical fashion have never experienced a crash", it could be that with different data, it does different things...
I'd suggest that you setup logging to a textfile in a "special" diagnostic version.
Log everything, your parameters, your exceptions, and the steps you're going through. Maybe even the start and end of every function, and every other line.
Here's how it could look...
Loaded DLL
Started MyFunction1 with parameters: 1,4,hello
1
2
...
500
Ended MyFunction1
to make that,,, I'd setup a few functions (in their own unit):
// opens a text file (fixed name), and appends to it.
function InitializeLog;
// closes the file
function CloseLog;
//add a log line.
function Log(message:string='', startNewFunction:boolean:False);
you would call it like this:
function MyFunction1(Integer,Integer,String);
begin
try
Log('Loaded DLL');
//use inttostr and do some string concats to get the params
Log('Started MyFunction1 with parameters: 1,4,hello',true);
//Then every other line:
Log;
//this would increment a global variable FuncLine:Integer
//and write it to the file.
except
On E:Exception (Log('***'+E.Message));
end;
end;
Something like this should have a {$DEFINE} to enable these logging functions, to enable/disable the diagnostic logging.
This could also be useful.
Look at Quality Central for report 58409.
It's about FPU Mask and Dll's.
To explain it in short:
The settings of the FPU Mask determ how floating point exceptions are handled.
If you have for example an Applicaion_A(coded by some else) which loads Dll_A(also coded by some else) and Dll_B(coded by you), and your Dll changes the FPU Mask, then this change is valid for Application_A and Dll_A as well.
Let's make an example:
You have installed for example WinZIP,SubVersion etc. which registers additional functions in the windows file explorer (popup-menu on right mouse click) and you now call TOpenDialog from inside your application.exe, then this additional functions might compromise your FPU settings.
Hope this helps.
(Additional hint: Take Sysinternal to see what dll's are loaded by your app)
Have you considered using MadExcept? If you catch the error in the interface methods you can either log the call stack or show a dialog to the user and return a standard EOleSysError back to the calling exe.
Something like this:
except
on e: Exception do
begin
MadExcept.HandleException();
raise EOleSysError.Create('InitializeObject Failed',
ErrorNumberToHResult(1 + CODE_BASE), 1);
end;
If the application hangs but not not throw and exception you can see what is happening by using the MadExcept utility madTraceProcess. That will let you generate a call stack for the running application. Your dll will not be on the main thread, but you will be able to see your call stack. That is a good way to tell if your dll is actually doing anything when the hang happens.
I have a COM dll that interacts with a exe that does not use MadExcept and this approach has worked well for me.
If their program crashes when you use their published interface, I'm pretty sure there's something wrong with it. Proving this is another thing, altogether.
Can you duplicate the problem reliably with a small Delphi app that you can give to the vendor? Seeing a reproducible failure could help convince them that they need to make a fix. At the very least, it could help pinpoint what they think you are doing "wrong" and tell you how to do it "right".
You could also try to duplicate the failure using C# or even VBScript.
If I understood the situation correctly, infortunately, there is not much you can do on your side if your DLL is not crashing and the called 3rd party program just stops being responsive. The crash is in their code but only triggered by your DLL calling it. The debug Log should really be done in their app.
What you can do though is to log all the calls your DLL make to this 3rd party program with the parameters and some context information.
Then looking at the last trace before the crash might give you some information...
I don't know how madExcept etc work, but I use jclDebug.pas + JclHookExcept.pas (from JEDI JCL library) a lot. It makes a Windows API hook, so it catches all (!) exceptions, even if you make something like this:
try
raise exception.create('test');
except
//eat exception
end;
Normally you don't see this exception because it is "eaten"... But with the hook you get all exceptions. For example: I once got an "catastrophic failure" in Midas.dll, and via the hook I saw an "database connection lost" error in the dll before this exception, so I knew what happened. (btw: JclHookExcept.pas = hook, jclDebug.pas = strack trace).
I see now that JclHookExcept.pas also has an "JclHookExceptionsInModule" procedure, so you can force (?) to hook all exceptions from an specific library...
Some demo code:
procedure AnyExceptionNotify(ExceptObj: TObject; ExceptAddr: Pointer; OSException: Boolean);
begin
//log exception
end;
initialization
// Start Exception tracking
JclStartExceptionTracking;
JclTrackExceptionsFromLibraries;
JclStackTrackingOptions := [stStack, stRawMode, stAllModules];
// Assign notification procedure for hooked RaiseException API call. This
// allows being notified of any exception
JclAddExceptNotifier(AnyExceptionNotify);

VB6 Program Crashing: Part 2. Advice on fixing Access Violation (0xC00000005)

Related to this question. Any advice on fixing the problem below?
After a lot of experimentation with the program, I have discovered several things.
It crashes relatively consistently (90% of the time or so) upon running the line of code, Set Message = New CAPICOM.EncryptedData. Note that the line above this is merely Dim Message As CAPICOM.EncryptedData.
The function that makes that call does not crash when called earlier in the program's execution. Binary search for error does not work to find the problem, since calling the function in some places mysteriously, unreliably prevents the bug from happening. Sometimes rebuilding the program seems to impact if the bug shows up. Yes, it is a heisenbug. The same issues apply with temporal binary search for error. Spending 5 hours comparing two versions of the program only to discover that both versions have the bug even though only one of them is currently showing the symptoms is not very productive.
The crash is due to an access violation 0xC00000005
Running WinDbg (the windows debugger) shows that there is only one line of code which reads this memory location, LoadPicture(szTmpBMP). It is called at the end of a scary function which grabs the picture out of a resource and sticks it in a temp file. I was scared enough of this function that, for the sake of testing, I replaced it with a call to LoadPicture("testcra.bmp"), then didn't call the scary resource function for that bitmap. This did not help. Removing this call to loadpicture entirely also did not help, though the debugger could no longer find any points where the affected memory was being read, and the affected memory was no longer at the same location. This testing was done on a VM, so some memory reads are not necessarily going to be visible to the debugger.
Everything works perfectly on Vista (both my local machine and a Vista VM). The access violation only occurs on XP.
I'm using VB6 Version 8176, 6.0.8169
My current solution, which works, is to create all my capicom objects early, and never to create new instances of capicom.encrypteddata beyond the first. This works, but it is unlikely that the underlying problem was actually fixed.

Resources