xe2 versiones software full descargar delphi com delphi-xe2

versiones - delphi wikipedia



¿Está descompuesto COM en XE2 y cómo podría solucionarlo? (2)

Actualización: XE2 Actualización 2 corrige el error que se describe a continuación.

El programa a continuación, recortado del programa real, falla con una excepción en XE2. Esta es una regresión de 2010. No tengo XE para probar pero espero que el programa funcione bien en XE (gracias a Primož por confirmar que el código funciona bien en XE).

program COMbug; {$APPTYPE CONSOLE} uses SysUtils, Variants, Windows, Excel2000; var Excel: TExcelApplication; Book: ExcelWorkbook; Sheet: ExcelWorksheet; UsedRange: ExcelRange; Row, Col: Integer; v: Variant; begin Excel := TExcelApplication.Create(nil); try Excel.Visible[LOCALE_USER_DEFAULT] := True; Book := Excel.Workbooks.Add(EmptyParam, LOCALE_USER_DEFAULT) as ExcelWorkbook; Sheet := Book.Worksheets.Add(EmptyParam, EmptyParam, 1, EmptyParam, LOCALE_USER_DEFAULT) as ExcelWorksheet; Sheet.Cells.Item[1,1].Value := 1.0; Sheet.Cells.Item[2,2].Value := 1.0; UsedRange := Sheet.UsedRange[LOCALE_USER_DEFAULT] as ExcelRange; for Row := 1 to UsedRange.Rows.Count do begin for Col := 1 to UsedRange.Columns.Count do begin v := UsedRange.Item[Row, Col].Value; end; end; finally Excel.Free; end; end.

En XE2 32 bit el error es:

Proyecto COMbug.exe provocó la clase de excepción $ C000001D con mensaje ''excepción de sistema (código 0xc000001d) en 0x00dd6f3e''.

El error ocurre en la segunda ejecución de UsedRange.Columns .

En XE2 64 bit el error es:

El proyecto COMbug.exe generó la clase de excepción $ C0000005 con el mensaje ''c0000005 ACCESS_VIOLATION''

De nuevo, creo que el error ocurre en la segunda ejecución de UsedRange.Columns , pero el depurador de 64 bits UsedRange.Columns por el código de una manera un poco extraña, así que no estoy 100% seguro de eso.

He enviado un informe de control de calidad para el problema.

Me parece mucho como si algo en la pila de COM / automatización / interfaz de Delphi estuviera completamente roto. Este es un completo stop-show para mi adopción de XE2.

¿Alguien tiene alguna experiencia con este problema? ¿Alguien tiene consejos y consejos sobre cómo puedo tratar de solucionar el problema? La depuración de lo que realmente sucede aquí está fuera de mi área de experiencia.


Solución

rowCnt := UsedRange.Rows.Count; colCnt := UsedRange.Columns.Count; for Row := 1 to rowCnt do begin for Col := 1 to colCnt do begin v := UsedRange.Item[Row, Col].Value; end; end;

Esto también funciona (y puede ayudarlo a encontrar una solución alternativa en casos de uso más complicados):

function ColCount(const range: ExcelRange): integer; begin Result := range.Columns.Count; end; for Row := 1 to UsedRange.Rows.Count do begin for Col := 1 to ColCount(UsedRange) do begin v := UsedRange.Item[Row, Col].Value; end; end;

Análisis

Se bloquea en System.Win.ComObj en DispCallByID al ejecutar _Release en

varDispatch, varUnknown: begin if PPointer(Result)^ <> nil then IDispatch(Result)._Release; PPointer(Result)^ := Res.VDispatch; end;

Aunque la versión PUREPASCAL de este mismo procedimiento en Delphi XE (XE usa una versión de ensamblador) es diferente ...

varDispatch, varUnknown: begin if PPointer(Result)^ <> nil then IDispatch(Result.VDispatch)._Release; PPointer(Result)^ := Res.VDispatch; end;

... el código de ensamblador en ambos casos es el mismo (EDITAR: no es cierto, vea mis notas al final):

@ResDispatch: @ResUnknown: MOV EAX,[EBX] TEST EAX,EAX JE @@2 PUSH EAX MOV EAX,[EAX] CALL [EAX].Pointer[8] @@2: MOV EAX,[ESP+8] MOV [EBX],EAX JMP @ResDone

Curiosamente, esto se bloquea ...

for Row := 1 to UsedRange.Rows.Count do begin for Col := 1 to UsedRange.Columns.Count do begin end; end;

... y esto no.

row := UsedRange.Rows.Count; col := UsedRange.Columns.Count; col := UsedRange.Columns.Count;

La razón de esto es el uso de variables locales ocultas. En el primer ejemplo, el código se compila para ...

00564511 6874465600 push $00564674 00564516 6884465600 push $00564684 0056451B A12CF35600 mov eax,[$0056f32c] 00564520 50 push eax 00564521 8D8508FFFFFF lea eax,[ebp-$000000f8] 00564527 50 push eax 00564528 E8933EEAFF call DispCallByIDProc

... y eso se llama dos veces.

En el segundo ejemplo, se usan dos ubicaciones temporales diferentes en la pila (compensaciones de ebp - ????):

00564466 6874465600 push $00564674 0056446B 6884465600 push $00564684 00564470 A12CF35600 mov eax,[$0056f32c] 00564475 50 push eax 00564476 8D8514FFFFFF lea eax,[ebp-$000000ec] 0056447C 50 push eax 0056447D E83E3FEAFF call DispCallByIDProc ... 0056449B 6874465600 push $00564674 005644A0 6884465600 push $00564684 005644A5 A12CF35600 mov eax,[$0056f32c] 005644AA 50 push eax 005644AB 8D8510FFFFFF lea eax,[ebp-$000000f0] 005644B1 50 push eax 005644B2 E8093FEAFF call DispCallByIDProc

El error se produce cuando se borra una interfaz interna almacenada en esta ubicación temporal, lo que ocurre solo cuando se ejecuta el caso "para" por segunda vez porque ya hay algo almacenado en esta interfaz: se colocó allí cuando se llamó "para" por primera vez. En el segundo ejemplo, se utilizan dos ubicaciones, por lo que esta interfaz interna siempre se inicializa en 0 y no se llama en absoluto a la versión.

El verdadero error es que esta interfaz interna contiene basura y cuando se lanza Release, ocurre sh! T.

Después de investigar un poco más, me di cuenta de que el código ensamblador que libera la interfaz anterior no es el mismo: a la versión XE2 le falta una instrucción "mov eax, [eax]". IOW,

IDispatch(Result)._Release;

es un error y realmente debería ser

IDispatch(Result.VDispatch)._Release;

Nasty error RTL.


La mayor parte de esto está por encima de mi cabeza, pero me pregunto si se requerirá una llamada a CoInitialize. La búsqueda en la web de CoInitialize devolvió esta página:

http://chrisbensen.blogspot.com/2007/06/delphi-tips-and-tricks.html

Casi parece que esa página describe el problema del OP y el análisis de gabr en lo que se refiere a una llamada a .Release. Mover la funcionalidad del código en su propio procedimiento podría ayudar. No tengo XE o XE2 para probar.

Editar: Ratas: la intención es agregar esto como un comentario al anterior.