Ver Mensaje Individual
  #3  
Antiguo 03-11-2013
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.609
Reputación: 30
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Qué tal, ecfisa. Me agrada que te hayas sumado a esta pesquisa.

Después de estudiar un poco más el problema, veo que conviene olvidarnos de CreateOLEObject y los ProgIDs. Verás, cuando ejecutamos la función CreateOLEObject de Delphi, estamos llamando indirectamente la función CLSIDFromProgID de la API de Windows, que como ya has visto sirve para convertir un ProgID en su respectivo GUID de clase COM (CLSID). Según la referencia técnica ésta función busca en el registro de Windows ("Looks up a CLSID in the registry, given a ProgID"), aunque seguramente es una búsqueda más eficiente que la que podríamos hacer con las funciones y clases que normalmente se usan para leer y escribir entradas del registro.

ProgIDToClassID es una envoltura Delphi de la función CLSIDFromProgID, y CreateOLEObject la usa para obtener el CLSID con el cual llamar a CoCreateInstance, la función de la API de Windows para crear una instancia de objeto COM:
Código Delphi [-]
function CreateOleObject(const ClassName: string): IDispatch;
var
  ClassID: TCLSID;
begin
  ClassID := ProgIDToClassID(ClassName);
  OleCheck(CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER or
    CLSCTX_LOCAL_SERVER, IDispatch, Result));
end;
Ahora, si examinamos cómo trabaja predeterminadamente el componente nativo TXMLDocument (del cual no quise derivar a TghXMLDoc por razones de diseño), podemos ver que éste llama a CoCreateInstance sin pasar por CreateOLEObject o ProgIDToClassID, y además hace algo como lo que aquí pretendemos: intentar la creación del objeto con diferentes versiones de MSXML:
Código Delphi [-]
const
  ...
  CLASS_DOMDocument: TGUID = '{F6D90F11-9C73-11D3-B32E-00C04F990BB4}';
  CLASS_DOMDocument26: TGUID = '{F5078F1B-C551-11D3-89B9-0000F81FE221}';
  CLASS_DOMDocument30: TGUID = '{F5078F32-C551-11D3-89B9-0000F81FE221}';
  CLASS_DOMDocument40: TGUID = '{88D969C0-F192-11D4-A65F-0040963251E5}';
  CLASS_DOMDocument60: TGUID = '{88D96A05-F192-11D4-A65F-0040963251E5}';  // No presente en Delphi 7
...
function TryObjectCreate(const GuidList: array of TGuid): IUnknown;
var
  I: Integer;
  Status: HResult;
begin
  Status := S_OK;
  for I := Low(GuidList) to High(GuidList) do
  begin
    Status := CoCreateInstance(GuidList[i], nil, CLSCTX_INPROC_SERVER or
      CLSCTX_LOCAL_SERVER, IDispatch, Result);
    if Status = S_OK then Exit;
  end;
  OleCheck(Status);
end;

function CreateDOMDocument: IXMLDOMDocument;
begin
  Result := TryObjectCreate([CLASS_DOMDocument60, CLASS_DOMDocument40, CLASS_DOMDocument30,
    CLASS_DOMDocument26, Winapi.msxml.CLASS_DOMDocument]) as IXMLDOMDocument;
  if not Assigned(Result) then
    raise DOMException.Create(SMSDOMNotInstalled);
end;
El secreto es que Delphi declara esas constantes TGUID, que son en sí las CLSIDs que Microsoft asignó a las distintas versiones del objeto DOMDocument de MSXML. Las CLSIDs son fijas y por tanto no necesitamos obtenerlas buscando ProgIDs en el registro de Windows, sólo conocer cuál es su valor GUID y usar éste para llamar a CoCreateInstance. Aun así podríamos buscar cada GUID en el registro antes de crear el objeto COM, pero esto no tendría mayor beneficio que intentarlo directamente, más o menos como esas funciones CreateDOMDocument y TryObjectCreate.

Esto comienza a allanar el camino. Podríamos decir que no vale la pena consultar el registro para convertir ProgIDs a CLSIDs que ya conocemos, y que TghXMLDoc debería llamar a CoCreateInstance intentando con diferentes CLSIDs. Pero todavía hay que resolver la cuestión de cuál es la mejor estrategia considerando, por ejemplo, cómo permitirle al programador indicar qué versión de MSXML debe utilizar nuestra clase o en qué orden de preferencia.

En las constantes que Delphi declara no hay una de nombre CLASS_DOMDocument50, y eso es porque la versión 5.0 de MSXML sólo puede instalarse con Microsoft Office, es decir, no es formalmente estándar en Windows. Sin embargo podría ser utilizada también en equipos que tengan ese paquete instalado. Entre sus características exclusivas, destaca por ejemplo la capacidad de hacer firma digital sobre los archivos XML, algo que por alguna razón Microsoft retiró en la versión 6.

Habiendo hecho este breve análisis, propongo que TghXMLDoc intente crear el objeto COM usando, predeterminadamente, sólo las CLSIDs CLASS_DOMDocument60, CLASS_DOMDocument40 y CLASS_DOMDocument30, en ese orden de preferencia. En esta lista predeterminada no tendría sentido contemplar versiones anteriores a la 3.0 por estar ya obsoletas. Pero sí tendrá sentido que un programador pueda indicar una versión en particular de modo expreso, cambiar el orden de preferencia o establecer su propia lista de CLSIDs.

¿Qué usar entonces?

a) parámetro(s) adicional(es) en el constructor
b) método virtual "GetCOMInstance" llamado por el constructor
c) método función virtual "COMCLSIDs" que regrese una matriz (array) de TGUIDs
d) una variable matriz global que pueda ser modificada por el programador
e) esa matriz pero como campo o propiedad de clase (no soportada en Delphi 7)
f) una combinación de los anteriores
g) otro mecanismo

Agradezco de antemano las ideas que puedan seguir aportando.

Un saludo.
Responder Con Cita