Typically, these kinds of errors come from one of two things. Either there is a timing difference between the record and the play back or the object is dynamically named.
For the first thing, playback of recorded scripts typically runs MUCH faster than the original record. So, if you're clicking on a button and then waiting for a screen to come up (like from an SQL query or something), if the next step of the test involves something on that new screen, it may try to operate on it before the screen is drawn. This will generate the "Object does not exists" or "Window invisible errors." The solution is to edit your recorded test to include either hard-coded "Delay" calls or to add in code to "Wait" for new screens (WaitWindow, WaitVCLObject, WaitAliasChild are all examples of routines built in to TestComplete).
The second thing is typically found when testing web apps but it happens in other desktop apps as well. Essentially, when an object is created, the name of the object (or other identifying factors) is dynamically generated at the time of creation. Each time through the software, the name may have a different value to it based upon some encryption scheme or .NET session ID or some other such thing. The solution to this is to use NameMapping in TestComplete to map your objects to a particular set of identifiers that are not going to be as dynamic. Or, for that matter, NameMapping can use wild cards and other techniques to make object detection "smarter". Check out the following video on name mapping (from a webinar that was given last month) on how name mapping can solve this problem as well.
http://www.youtube.com/watch?v=XT-Pz8_OS_I