Visualizzazione dei risultati da 1 a 10 su 10
  1. #1
    Utente di HTML.it L'avatar di VaLvOnAuTa
    Registrato dal
    Jun 2002
    Messaggi
    2,003

    [Delphi] Errore: MSXML not installed

    Salve

    Sempre per la famosa applicazione client-server (che sto recodando usando i componenti indy) ho sviluppato un protocollo che si basa sullo scambio tra client e server di dati formattati con xml.

    Un esempio di formattazione dei dati potrebbe essere questa:
    codice:
    <valvonauta>
     <header>
      <comando>LOGIN</comando>
     </header>
     <info>
      <username>VaLvOnAuTa</username>
     </info>
    </valvonauta>
    Ora ho creato un datamodule con un XMLDocument che ha due funzioni:
    Formattare il dato in xml ed estrarre i dati da una stringa (ovviamente formattata in xml).
    Il codice è questo:
    codice:
    unit cProtocollo;
    
    interface
    
    uses
      SysUtils, Classes, xmldom, XMLIntf, msxmldom, XMLDoc;
    
    type
      TProtocollo = class(TDataModule)
        xmlDoc: TXMLDocument;
      private
      public
        Comando                       : string;
        function Tipo(pXml: string)   : string;
        function ToXml                : string;
      end;
    
    var
      Protocollo: TProtocollo;
    
    implementation
    
    function TProtocollo.Tipo(pXml: string): string;
    var nNodo: IXMLNode;
    begin
     xmlDoc.Active:=False;
     xmlDoc.XML.Text:=pXml;
     try
      xmlDoc.Active:=True;
      nNodo:=xmlDoc.DocumentElement.ChildNodes['Header'];
      Tipo:=nNodo.ChildNodes['Comando'].Text;
      xmlDoc.Active:=False;
     except
      Tipo := '';
     end;
    end;
    
    function TProtocollo.ToXml: string;
    var vXML: string;
    begin
     vXml:=       '<valvonauta>';
     vXml:=vXml + '  <Header>';
     vXml:=vXml + '    <Comando>'+ Comando +'</Comando>';
     vXml:=vXml + '  </Header>';
     vXml:=vXml + '</valvonauta>';
     ToXml:=vXML;
    end;
    
    {$R *.dfm}
    
    end.
    La funzione "Tipo" mi serve per riconoscere il comando ricevuto.
    Ora, il client utilizza lo stesso datamodule e riesce ad estrerre il comando correttamente.
    Il server invece, mi da l'errore nel titolo.
    Dato che sulla stessa macchina il client funziona (riesce ad estrarre correttamente il dato tra i tag <Comando> e </Comando>) ed il server no, credo ci sia qualcosa che mi sfugge, ma non è certo l'installazione dell' MSXML.

  2. #2
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,472
    Devi installare il componente richiesto dal CD di Delphi oppure scaricandolo dal sito Microsoft (via preferibile) sulla macchina in cui deve eseguire la tua applicazione.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  3. #3
    Utente di HTML.it L'avatar di VaLvOnAuTa
    Registrato dal
    Jun 2002
    Messaggi
    2,003
    Originariamente inviato da alka
    Devi installare il componente richiesto dal CD di Delphi oppure scaricandolo dal sito Microsoft (via preferibile) sulla macchina in cui deve eseguire la tua applicazione.

    Ciao!
    Ma non mi spiego il motivo per cui quel componente funziona su un'applicazione e non su un'altra (ho aggiunto al progetto sia del client che del server lo stesso datamodule).
    Oltretutto l'applicazione (instabile) che avevo già creato prima funziona basandosi sullo stesso concetto (utilizzando gli stessi componenti) e non mi ha dato mai problemi (almeno non sull'xml)

    Comunque adesso lo cerco e lo installo... non si sa mai...

  4. #4
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,472
    Installa l'ultima versione su entrambe le macchine e compila il programma, poi ritenta la distribuzione.

    L'alternativa è quella di utilizzare un parser differente, come Open XML.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  5. #5
    Utente di HTML.it L'avatar di VaLvOnAuTa
    Registrato dal
    Jun 2002
    Messaggi
    2,003
    Riprendo questa discussione perchè ho trovato qualcosa di interessante.
    Il problema, cercando in giro sulla rete, riguarda il fatto che un oggetto COM (quale un XMLDocument), in un'applicazione multithread, ha bisogno di essere inizializzato in ogni thread.

    Ora, l'applicazione che ho creato io è necessariamente multithread (in quanto, suppongo, il componente "IdTcpServer" utilizzi più thread per gestire più connessioni contemporanee ed ecco perchè sui client funzionava: il componente "IdTcpClient" non ha bisogno di gestire più threads dato che la connessione è unica).

    Cercando ulteriormente ho trovato una FAQ in inglese che dice quanto segue:
    [supersaibal]
    Ever get the "CoInitialize has not been called" (800401F0 hex) error?
    Sì.. ricompilando la stessa applicazione con delphi 7, l'errore cambia ma la motivazione dell'errore è la stessa.. almeno a detta della Borland

    Each thread in your application that interacts with COM (i.e. creates COM objects, calls COM APIs, etc.) must initialize itself into an apartment. A thread can either join a single threaded apartment (STA) or the multithreaded apartment (MTA).

    The STA is system-synchronized based on a windows message queue. Use the STA if your object or thread relies on thread-relative resources such as UI elements. The following shows how to initialize a thread into an STA:

    procedure FooThreadFunc; //or TFooThread.Execute
    begin
    CoInitializeEx (NIL, COINIT_APARTMENTTHREADED);
    ... do your stuff here ...
    CoUninitialize;
    end;

    The MTA is system-guaranteed to be ruthless. Objects in the MTA will receive incoming calls from anywhere anytime. Use the MTA for non-UI related objects, but synchronize carefully! The following shows how to initialize a thread into the MTA:

    procedure FooThreadFunc; //or TFooThread.Execute
    begin
    CoInitializeEx (NIL, COINIT_MULTITHREADED);
    ... do your stuff here ...
    CoUninitialize;
    end; [/supersaibal]
    Ok.. niente di più semplice.. basta richiamare la funzione CoInitializeEx() all'inizio della funzione che gestisce il thread e chiamare la CoUninitialize alla fine della funzione.
    Quindi il codice della mia funzione dovrebbe essere:
    codice:
    procedure TServer.SrvExecute(AThread: TIdPeerThread);
    var
     vText,
     vTipo: string;
    begin
     CoInitializeEx(NIL, COINIT_APARTMENTTHREADED);
     vText := AThread.Connection.ReadLn;
     vTipo := Protocollo.Tipo(vText);
     showMessage(vTipo);
     if (vTipo = 'LOGIN') then  
      begin
       showMessage(vTipo);
      end;
     CoUninitialize;
    end;
    Ora resta da scoprire in quale unit si cela sta funzione

  6. #6
    Utente di HTML.it L'avatar di VaLvOnAuTa
    Registrato dal
    Jun 2002
    Messaggi
    2,003
    Ok trovato.

    E' nella unit ComObj.. peccato che non ci sia una guida di referenza... forse su msdn.microsoft...

  7. #7
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,472
    Cerca in ComObj oppure in ActiveX.

    Sono le unit che fanno parte del framework DAX, le classi Delphi per l'uso (e creazione) di componenti COM e le dichiarazioni per l'accesso alle relative API.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  8. #8
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,472
    Originariamente inviato da VaLvOnAuTa
    E' nella unit ComObj.. peccato che non ci sia una guida di referenza... forse su msdn.microsoft...
    Si tratta di funzioni API, quindi tutte le informazioni sul loro utilizzo sono reperibili su MSDN oppure scaricando e installando la Win32 SDK Documentation aggiornata dal sito Microsoft.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  9. #9
    Utente di HTML.it L'avatar di VaLvOnAuTa
    Registrato dal
    Jun 2002
    Messaggi
    2,003
    Grazie mille alka.
    In effetti nella unit ComObj si trova solo CoInitialize mentre nella unit ActiveX si trovano entrambe le funzioni.

    Ora il problema della chiamata a Coinitialize è risolto.
    Però pare che il documento COM (xml in questo caso) non venga attivato (nonostante nel codice io setti xmldoc.Active := true).

    Girerò ulteriormente su internet e vedo se trovo una soluzione anche a questo. Nel caso ci riuscissi, metterò la soluzione sul forum per i posteri

  10. #10
    Utente di HTML.it L'avatar di VaLvOnAuTa
    Registrato dal
    Jun 2002
    Messaggi
    2,003
    Ok ho trovato la soluzione.
    Magari spiego il problema dato che ho letto in giro su internet diversi problemi simili al mio senza una soluzione.

    Innanzitutto l'applicazione è di tipo Client-Server (componenti "IdTcpClient" e "IdTcpServer" rispettivamente delle palette "Indy Clients" e "Indy Servers") dove lo scambio di informazioni tra i due host avviene con dei messaggi formattati in XML (componente "XMLDocument" della palette "Internet").
    Il client non ha alcun problema a processare il documento XML perchè utilizza un unico thread.
    Il problema sorge sul server che, ricevendo più connessioni, deve gestire ciascun socket come un thread a sè.
    Ebbene, il problema è che un ComObject (quale è il componente XMLDocument) deve essere inizializzato (e poi concluso) in ogni thread (quindi in pratica ad ogni esecuzione del server - evento "IdTcpServer.OnExecute").
    Quindi diventa necessario includere la libreria "ActiveX" nella clausola "uses" dell'applicazione server e utilizzare le funzioni "CoInitialize" e "CoUnitialize" prima di eseguire qualunque operazione.
    codice:
    procedure Form1.IdTcpServer1Execute(AThread: TIdPeerThread);
    begin
     CoInitialize(NIL);
     
     //operazioni da eseguire sul thread 
    
     CoUninitialize;
    end;
    Per quanto riguarda l'errore di documento non attivo, è stato un mio errore: attivavo l'XMLDocument prima di assegnargli il testo nella proprietà "XML".
    That's all folks

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.