2010-03-29 5 views
5

Débutant question: J'ai une application de formulaires. Il a un thread séparé qui effectue un appel de services Web, puis publie les résultats de l'appel au formulaire principal.Dois-je libérer un objet Delphi auto-instancié à partir d'un appel de services Web?

Dans mon fil, après X secondes se sont écoulées (en utilisant un TTimer), j'appelle:

procedure TPollingThread.OnTimer(Sender: TObject); 
var 
SystemProbeValues : TCWProbeValues; 
begin 
SystemProbeValues := Remote.Run.GetSystemProbeValues; 
PostMessage(ParentHandle, WM_APIEVENT ,Integer(apiMultiCellStatus), Integer(SystemProbeValues)); 
end; 

La fonction Remote.Run.GetSystemProbeValues ​​a le prototype suivant:

function GetSystemProbeValues : TCWProbeValues; stdcall; 

Et TCWProbeValues est un tableau dynamique d'objets TCWProbeValue (qui descendent tous de TRemotable).

Dans ma principale forme, je reçois le message bien et jeté le LParam Retour à TCWProbeValues:

procedure TFrmCWMain.OnAPIEvent(var msg: TMessage); 
begin 
ProbeValues := TCWProbeValues(msg.LParam); 
end; 

Ma question est, étant donné que le tableau dynamique et ses objets ont été créés par le système Delphi HTTORIO, Qui est responsable de les libérer? Est-ce que Delphi considérait que la mémoire était réutilisable après le retour de ma fonction OnTimer? (Et dans ce cas, sa pure chance que mon gestionnaire de message principal puisse réellement lire la mémoire référencée par le LParam du message?) Ou plutôt, est-ce ma responsabilité de libérer l'objet auto-instancié par la requête HTTPRIO?

Merci beaucoup, s'il vous plaît crier si ce qui précède a besoin de plus de détails/code et je vais y ajouter!

Cheers, Duncan

Répondre

4

TRemotable assure la gestion de la vie par sa propriété DataContext, de sorte que le temps d'exécution SOAP libérera l'objet lui-même. Tant que l'objet de contexte de données existe, tout ce qu'il a attribué existera également. Si vous souhaitez revendiquer la propriété et la responsabilité d'un objet, effacez simplement sa propriété DataContext. (C'est probablement ce que vous voulez faire dans ce cas parce que votre message API-événement peut se traitée après l'événement SOAP a pris fin.)


Un problème dans votre code est que vous passez une dynamique tableau via un message posté. Lorsque votre procédure OnTimer retourne à son appelant, le tableau dynamique référencé par SystemProbeValues verra son compte de référence décrémenté. Si l'autre thread n'a pas encore traité le message (et il ne l'a probablement pas fait), le tableau dynamique peut déjà être détruit au moment où se déplace pour traiter ce message.

La solution la plus simple consiste à supprimer la référence dans le gestionnaire d'événements du temporisateur sans réduire le nombre de références, puis à effectuer l'opération inverse dans le gestionnaire de messages. Une fois que vous affichez le message, désactivez la variable:

LParam(SystemProbeValues) := 0; 

Dans votre gestionnaire de messages, désactivez l'ancienne valeur de la variable ProbeValues globale et attribuer la nouvelle valeur comme ceci:

ProbeValues := nil; 
LParam(ProbeValues) := Msg.LParam; 

Une autre problème qui se cache dans votre code peut être l'utilisation de TTimer dans un thread non-VCL. Cette classe crée un handle de fenêtre à partager entre toutes les instances de la classe.À moins que votre thread minuteur ne soit le seul thread du programme qui utilise TTimer, vous aurez probablement des problèmes, soit avec des fonctions tournant dans le mauvais thread, soit avec des fonctions qui ne fonctionnent pas du tout. Au lieu de TTimer, vous pouvez utiliser SetTimer pour créer une minuterie OS manuellement, ou vous pouvez créer un waitable timer, qui peut être plus approprié pour une utilisation dans un thread qui n'a pas besoin de rester sensible aux actions de l'utilisateur.

Questions connexes