Second on the byte encoding. I would keep your incoming bytes as just.. bytes and not ASCII. The old MScomm as well as the newer (terribly implemented) .NET serial controls are all geared towards true terminal comms - ASCII, linefeed, carriage return etc.. rather than raw bytes, but of course can be configured for such.
Whilst its nice to be able to use string functions, I have had to use very specific coding to get actual single byte ASCII values, rather than the standard 16-bit encoding. I believe it was.. crudely converted from C#...
s = System.Text.Encoding.GetEncoding(28591).GetChars(dataBytes.ToArray, 0, EOLlocation) 'gets all the bytes up until linefeed character
Note the dodgy number, which I got from an hour of googling.
In the embedded world ASCII is simple, but there are many forms of ASCII encoding on PC's.
As for dealing with frames and fixed-size packet data, I never relied on built in events to fire when a terminal character was found, or when a certain number of bytes has been received. This is mostly related to the newer .NET controls (3.5+) but I vaguely remember the same deal with MScomm (when I was 12 :/). It sometimes didn't fire when a certain number of bytes was received, or it did, but only returned half of what it had. Also, both versions rarely reported the correct number of bytes in its buffer: you get the number of bytes it claims it has recieved, create an array of that size and copy over, only for an exception to be thrown because in the time it took to move the data through many levels of buffers - you've received a few more bytes, and the array you created is too small.
Crude solution which might not be so great on VB6 was to set up a background worker thread on a timer. This simply, periodically grabbed all the data from the receive buffer (by seeing how many it claims were received, adding to a large array, resizing the array based on how many were actually received, then copying), and added that chunk to a byte list, which then triggered an event in the main thread to grab that, add to to the end of the main buffer, check for start/termination values and spit out packets when it found them. Effectively doing it manually because it was the only way I could get all the bytes in at > 19.2k. (seems to work at >1Mbps using USB-serial adapters). It shouldn't have to be this way, but also was less prone to hanging.
That said people still use MScomm today because for legacy apps its more reliable than the later .NET and...ahem.. Java... for serial comms.