是Excel自身的问题。Excel设计为可重入的,它有一个内核(类),当系统中某个进程创建了第一个Excel对象,Windows就把Excel的内核加载到内存中,以后再创建新的Excel对象,它就不会再重新加载,直接使用同样的内核,只是开辟空间供新的对象数据使用而已,也就是说,处理数据的功能即逻辑代码是同一个东西,但处理的实例数据不同——这就是Windows面向对象的运行机制。所有面向对象的编程,本质上都是这样实现的。这类似于老师教学生,做竖式加法,教的是方法,那就是逻辑代码,亦即类设计代码,实际做的时候,是套入具体的数据,创建新的竖式,照着同样的方法进行处理,那些一道一道的竖式结果,就是具体的实例,而进行运算的手法是完全是一样的,都是那个老师教出来的。Excel的运作,可能也是这样的,它在读写外部设备的时候(通常这样的动作线程不可重入,因为旧式的程序设计多数没有异步文件机制),当Excel在进行这种动作的时候,不巧时间片被切换给用户启动另一个Excel对象,这也需要时间,两个进程在抢时间片,一个动作无法在系统供给的连续CPU时间内完成,再重入时就出错了。
可以举个例子,有某个函数fun(),它使用一个静态变量,比如计数器counter,统计某个数据,这可以在该函数被操作系统切换暂停后重入时把记忆的数据恢复原状继续运行。但现在的问题是,这个函数也是静态的,它被多个对象实例同时使用,那么,A进程使用它的时候记下了counter=10,被切换到B进程,极可能此时的counter值被B拿去当作原来的环境恢复使用了,然后又被更改掉,那么后面的一连串错误就可想而知了。现在是我们不能确保Excel没有使用这种模式的设计。其实Windows记忆自己创建了多少个窗口也是这样的,它内部有一个表格,专门记录这些数据,是只能给它自己使用的,应用程序禁止接触那些东西,所以在理论上必须由操作系统来改善这个问题。
可以实验一下:在Windows中启动一个Excel,随便处理什么文件或数据,不关闭,然后再双击Excel(不打开什么),我试过不会有新的Excel出现,但如果双击某个.xls文档,就会出现一个新的Excel窗口了。这说明,Excel实际上有检查自己是否已经启动的机制,除非真的需要处理不同的数据,否则它不会创建空白的自己。如果用CreateObject("Excel.Application")创建对象,这个语句要求启动一个空白的Excel,前提应是系统中没有Excel在运行,此时可以改用直接打开Excel文档的方式创建。而在Excel进行磁盘读写的时候出错,我认为是Excel没有实现异步文件读写的缘故,新的.NET框架开始支持异步文件了,但可能应该也要使用最新的Office才行,不过这时是否仍然支持COM模式被VFP操纵就不得而知了,还没用过。