Erreurs, bugs, questions - page 2540

 
Comment faire pour que le terminal libère le fichier mqd ? Ou mieux encore, s'il existait un moyen interne de le supprimer de l'interface ?
 
Stanislav Korotky:
Comment faire pour que le terminal libère le fichier mqd ? Ou mieux encore, s'il existait un moyen interne de le supprimer de l'interface ?

Je peux approximativement deviner le sujet de la question. Mieux vaut le reformuler.

 
Je pense qu'il y a un problème avec la désinitialisation des dll dans les services, aidez-moi à comprendre.
Le problème est le suivant. Après avoir appuyé sur la commande "Stop" dans le menu Service, le terminal n'attend pas la fin de la fonction Fn() pour une raison quelconque.
Il tente prématurément de rompre la connexion avec la dll, ce qui entraîne un blocage du terminal ou un plantage complet (fermeture).
Bien qu'au point d'entrée DllMain, l'indicateur Detach dans DLL_PROCESS_DETACH définit explicitement un indicateur pour mettre fin à la boucle while.

Mais while n'a pas le temps de sortir de la boucle à temps pour exécuter les fonctions ci-dessous, après que tous les autres processus se soient terminés en plus.
Et terminer la fonction Fn() elle-même.
La fonction DestroyFunction() ; sert de contrôle dans cet exemple.

Le contenu de la dll

#define  EXP extern "C" __declspec(dllexport)

void DestroyFunction(void);
EXP void __stdcall Fn(int num);

bool Detach;

//---------------------------------------------------------------------
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
        switch (ul_reason_for_call)
        {
                case DLL_PROCESS_ATTACH:
                        Detach = false;
                        break;
                case DLL_THREAD_ATTACH:
                        break;
                case DLL_THREAD_DETACH:
                        break;
                case DLL_PROCESS_DETACH:
                        Detach = true;
                        break;
        }
        return TRUE;
}

//---------------------------------------------------------------------
void DestroyFunction()
{
        MessageBoxW(NULL, L"Start DestroyFunction", L"OK", MB_OK);

        return;
}

//---------------------------------------------------------------------
EXP void __stdcall Fn(int num)
{
        int count = num;

        while (Detach == false)
        {
            //Имитация работы цикла
            count++;    

            if (count > 0)
                MessageBoxW(NULL, L"Start While iteration", L"OK", MB_OK);

            Sleep(10000);
        }       

 
        //После нажатия команды "Остановить" в меню Сервис, сюда уже не доходим, так как уже висим, или вылетел терминал.
        DestroyFunction();

        
        return;
}


Le contenu du programme Service.
Un retard supplémentaire par _StopFlag n'est pas utile.

//+------------------------------------------------------------------+
//|                                                      BugDll.mq5 |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property service
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
#property script_show_inputs


#import "BugDll.dll"
   void Fn(int num);
#import


//+------------------------------------------------------------------+
//| Service program start function                                   |
//+------------------------------------------------------------------+
int OnStart()
{      
   
   Fn(0);

   if(_StopFlag)
      Sleep(10000);
   
   return(0);
}
//+------------------------------------------------------------------+
Dossiers :
MQL5.zip  54 kb
 
Roman:
Je pense qu'il y a un problème avec la désinitialisation de la dll dans les services, aidez-moi.

la dll n'est pas (nécessairement) déchargée immédiatement après la fin du service (je peux me tromper)

Dans tous les cas, ce que vous faites avec DLL_PROCESS_DETACH est trop tard. Faites une fonction de désinit explicite dans la dll qui mettra ce drapeau et l'appellera explicitement quand le service se terminera.

 
Roman:

Le terminal commencera à décharger la librairie après le retour du thread de start(), je pense. Sinon, comment cela fonctionne-t-il ? Le programme est en cours d'exécution et commence à casser son environnement ? C'est absurde. Démarrez un thread séparé dans la librairie, sans poursuivre un thread de script dans une boucle, et il pourra se terminer normalement.

 
Vict:

Le terminal commencera à décharger la librairie après le retour du thread de start(), je pense. Sinon, comment cela fonctionne-t-il ? Le programme est en cours d'exécution et commence à casser son environnement ? C'est absurde. Démarrez un fil séparé dans la librairie, et il pourra se terminer normalement.

Le problème est que j'ai le même problème avec les threads, et à cause de cela je ne peux pas terminer correctement les autres processus (threads), qui ont un tas d'objets qui doivent être détruits.
Je ne peux pas terminer les autres processus correctement (c'est-à-dire que je ne peux pas tuer les autres processus).
Le terminal ne fonctionne pas correctement avec le point de sortieDLL_PROCESS_DETACH.

Je vais essayer ce que TheXpert a suggéré, mais le fait que le terminal décharge la dll immédiatement, indépendamment de DLL_PROCESS_DETACH, ce doit être une erreur du terminal.

LeXpert:

La dll n'est pas (nécessairement) déchargée immédiatement après la fin du service (je peux me tromper).

De toute façon, ce que vous faites avec DLL_PROCESS_DETACH est trop tard. Faire une fonction explicite deinit dans la dll, qui mettra ce drapeau et l'appellera explicitement à l'arrêt du service.

Merci pour l'astuce, je vais essayer de cette façon.

 
Roman:

Le fait est que j'ai le même problème avec les threads et qu'à cause de cela, je ne peux pas terminer correctement les autres processus (threads) qui ont un tas d'objets qui doivent être détruits.
Je ne peux pas terminer les autres processus correctement (c'est-à-dire que je ne peux rien faire pour eux).
Le terminal ne fonctionne pas correctement avec le point de sortie DLL_PROCESS_DETACH.

Je vais essayer ce que TheXpert a suggéré, mais le terminal décharge la dll en une fois, sans tenir compte de DLL_PROCESS_DETACH, ce doit être un bug du terminal.

Merci pour le conseil, je vais essayer de cette façon.

Qu'est-ce qui vous fait croire que le dll vit dans un fil séparé ? Vous avez un plantage de programme trivial qui n'est pas traité dans les conditions de boucle.

Et DllMain est exécuté lors de la connexion/déconnexion de la dll au processus DLL_PROCESS et lors de la création/termination du thread créé dans ce processus DLL_THREAD. Donc votre bool Detach, il n'existe pas forcément à l'intérieur de la dll, car le compilateur a pu le supprimer dans le cadre de l'optimisation, car lors de l'exécution de toutes les fonctions pendant la durée de vie de la dll il ne change pas et est égal à false.

 
Vladimir Simakov:

Qu'est-ce qui vous fait croire que le dll vit dans un fil séparé ? Vous avez un plantage de programme trivial qui n'est pas traité dans les conditions de boucle.

Et DllMain est lancé lorsque vous connectez/déconnectez la dll au processus DLL_PROCESS et lorsque vous créez/déconnectez un thread, créé dans ce processus DLL_THREAD. Donc votre bool Detach, il n'existe pas forcément à l'intérieur de la dll, car le compilateur a pu le supprimer dans le cadre de l'optimisation, car lors de l'exécution de toutes les fonctions pendant la durée de vie de la dll il ne change pas et est égal à false.

Il n'a été dit nulle part que le dll vit dans un fil séparé.
Nous communiquons avec Vict et nous nous comprenons)).
Je comprends qu'il s'agit d'un crash, mais je ne comprends pas pourquoi le drapeau dans DLL_PROCESS_DETACH ne fonctionne pas pour quitter la boucle while.
Quant aux DLL_THREAD, ils ne sont pas du tout disponibles pour mql, c'est écrit dans cet article, je l'ai vérifié et ils ne fonctionnent vraiment pas.
Mais avec le compilateur VS en option, cela pourrait aussi être une astuce.
J'aimerais entendre des explications de la part de représentants compétents plutôt que des suppositions ;))

 
Roman:
Je pense qu'il y a un problème avec la désinitialisation de la dll dans les services, aidez-moi à comprendre.
Le problème est le suivant. Après avoir appuyé sur la commande "Stop" dans le menu Service, le terminal n'attend pas la fin de la fonction Fn() pour une raison quelconque.
Il tente prématurément de rompre la connexion avec la dll, ce qui entraîne un blocage du terminal ou un plantage complet (fermeture).
Bien qu'au point d'entrée DllMain, le drapeau Detach dans DLL_PROCESS_DETACH définit clairement un drapeau pour mettre fin à la boucle while.

Mais while n'a pas le temps de sortir de la boucle à temps pour exécuter les fonctions ci-dessous, après que tous les autres processus se soient terminés en plus.
Et terminer la fonction Fn() elle-même.
La fonction DestroyFunction() ; sert de contrôle dans cet exemple.

Le contenu de la dll


Le contenu du programme Service.
Un retard supplémentaire par _StopFlag n'est pas utile.


Vous n'avez donc pas repris le contrôle du terminal, vous vous êtes "accroché" dans une boucle "infinie" à l'intérieur du Fn de la DLL.
De quel genre de résiliation normale parlons-nous ?

Si vous avez besoin d'un tel comportement, alors à l'intérieur du Fn dans la DLL, vous devez exécuter un thread séparé avec une boucle, qui doit être arrêté par le drapeau, qui est défini dans la fonction séparée FnStop et à DLL_PROCESS_DETACH.
 
Ilyas:
Vous n'avez donc pas récupéré le contrôle du terminal, vous vous êtes "accroché" dans une boucle "infinie" à l'intérieur du Fn de la DLL.
De quel genre de résiliation normale parlons-nous ?

Si vous avez besoin d'un tel comportement, vous devez exécuter un thread séparé avec une boucle à l'intérieur de Fn dans DLL, qui doit être arrêté par un drapeau, qui est défini dans une fonction séparée FnStop et avec DLL_PROCESS_DETACH.

Le fait que je ne récupère pas le contrôle, c'est fait par exemple, il est clair que while doit être exécuté dans un thread séparé, afin de ne pas bloquer le thread mql.
Mais j'obtiens le même comportement lorsque j'exécute dans un autre thread, le problème est dans DLL_PROCESS_DETACH, cet identifiant ne fonctionne pas, pour le flag Detach existant.
Oui, nous avons déjà écrit, que nous devons créer une fonction exportée séparée et l'utiliser pour contrôler ce drapeau.
Mais comme le montre cet exemple, l'indicateur dans DLL_PROCESS_DETACH ne fonctionne pas.
S'il y a une erreur dans le terminal, il est logique que DLL_PROCESS_DETACH transfère le drapeau vers un autre état.
La boucle while obtient cet état, sort de la boucle, tout ce qui est rencontré en cours de route est exécuté et termine la fonction Fn() elle-même.
Ce n'est qu'après cela que la dll doit être déchargée !
Mais ce n'est pas le cas, nous avons une sorte de déchargement anticipé des dll par des mécanismes cachés du terminal, et nous avons donc un crash.