The strategy I would use is exactly what you've done. Remove as much code as possible until the problem disappears then add that last bit back in and debug it.
However, it may not be your code that's at fault. One thing to watch out for - we found this problem on AIX and, even though you're running Windows, it may be similar.
We had a third party library which dynamically loaded another shared library which, in its initialization routine, set up an atexit function to be called when the process exits.
However, as our application loads and unloads these shared libraries, by the time the process exited, the shared library's atexit function was no longer in memory and we dumped core.
This shows up as an access violation after returning from main() so, if that's what's happening to you, it's almost certainly the same sort of thing. The C RTL startup code will walk the atexit list and call each of its functions, no matter what you've done with them.
Of course, if it's crashing before main() exits, then this is a moot point.
One thing you could consider (and we've actually done this on one occasion after a cost/benefit analysis of tracking down and fixing a particularly thorny bug): send out the debug release as your product. If it's not crashing, that may be a quick fix to get the product out there while you work on a more acceptable solution at your leisure.