Erreur CLIPBRD_E_CANT_OPEN lors de la définition du Presse-papiers à partir de .NET

StackOverflow https://stackoverflow.com/questions/68666

  •  09-06-2019
  •  | 
  •  

Question

Pourquoi le code suivant provoque-t-il parfois une exception avec le contenu "CLIPBRD_E_CANT_OPEN":

Clipboard.SetText(str);

Cela se produit généralement la première fois que le Presse-papiers est utilisé dans l'application et non après.

Était-ce utile?

La solution

En fait, je pense qu'il s'agit du erreur de l'API Win32 .

Pour définir les données dans le Presse-papiers, vous devez ouvrez-le d'abord . Un seul processus peut ouvrir le Presse-papiers à la fois. Ainsi, lorsque vous vérifiez que si le presse-papiers est ouvert par un autre processus pour une raison quelconque , votre tentative d'ouverture n'aboutira pas.

Il se trouve que les services Terminal Server gardent une trace du presse-papiers et que sur les anciennes versions de Windows (antérieures à Vista), vous devez ouvrir le presse-papiers pour voir ce qu’il contient dedans ... ce qui finit par vous bloquer. La seule solution consiste à attendre que les services Terminal Server ferme le Presse-papiers, puis réessayez.

Il est important de réaliser que cela n’est pas spécifique aux services Terminal Server: cela peut arriver avec n'importe quoi. Travailler avec le presse-papiers dans Win32 est une situation critique. Mais, étant donné que par conception, vous n'êtes censé déranger que dans le presse-papiers en réponse aux commentaires de l'utilisateur, cela ne présente généralement pas de problème.

Autres conseils

Ceci est dû à un bogue / une fonctionnalité du presse-papiers des services Terminal Server (et d’autres choses possibles) et à l’implémentation .NET du presse-papiers. Un retard dans l’ouverture du presse-papiers provoque l’erreur, qui est généralement transmise en quelques millisecondes.

La solution consiste à essayer plusieurs fois dans une boucle et à dormir entre les deux.

for (int i = 0; i < 10; i++)
{
    try
    {
        Clipboard.SetText(str);
        return;
    }
    catch { }
    System.Threading.Thread.Sleep(10);
} 

Je sais que cette question est ancienne, mais le problème existe toujours. Comme mentionné précédemment, cette exception se produit lorsque le Presse-papiers du système est bloqué par un autre processus. Malheureusement, il existe de nombreux outils de capture, programmes pour les captures d'écran et outils de copie de fichiers pouvant bloquer le presse-papiers de Windows. Vous obtiendrez donc l'exception à chaque fois que vous essayez d'utiliser Clipboard.SetText (str) lorsqu'un tel outil est installé sur votre PC.

Solution:

ne jamais utiliser

Clipboard.SetText(str);

utiliser à la place

Clipboard.SetDataObject(str);

En fait, il pourrait y avoir un autre problème. L'appel de structure (à la fois les variantes WPF et Winform) à quelque chose comme ceci (le code provient du réflecteur):

private static void SetDataInternal(string format, object data)
{
    bool flag;
    if (IsDataFormatAutoConvert(format))
    {
        flag = true;
    }
    else
    {
        flag = false;
    }
    IDataObject obj2 = new DataObject();
    obj2.SetData(format, data, flag);
    SetDataObject(obj2, true);
}

Notez que SetDataObject est toujours appelé avec true dans ce cas.

En interne, cela déclenche deux appels vers l'API win32, l'un pour définir les données et l'autre pour le vider de votre application afin qu'elle soit disponible après la fermeture de l'application.

J'ai vu plusieurs applications (un plugin chrome et un gestionnaire de téléchargement) écoutant l'événement du presse-papier. Dès que le premier appel aura été lancé, l'application ouvrira le presse-papiers pour examiner les données et le second appel à vider échouera.

Je n'ai pas trouvé de bonne solution, si ce n'est d'écrire ma propre classe de presse-papiers utilisant l'API Win32 directe ou d'appeler directement setDataObject avec false pour conserver les données après la fermeture de l'application.

J'ai résolu ce problème pour ma propre application à l'aide de fonctions Win32 natives: OpenClipboard (), CloseClipboard () et SetClipboardData ().

Ci-dessous la classe d'emballage que j'ai créée. Quelqu'un peut-il s'il vous plaît l'examiner et indiquer s'il est correct ou non . Surtout lorsque le code géré est exécuté en tant qu'application x64 (j'utilise n'importe quel processeur dans les options du projet). Que se passe-t-il lorsque je crée un lien vers des bibliothèques x86 à partir d'une application x64?

Merci!

Voici le code:

public static class ClipboardNative
{
    [DllImport("user32.dll")]
    private static extern bool OpenClipboard(IntPtr hWndNewOwner);

    [DllImport("user32.dll")]
    private static extern bool CloseClipboard();

    [DllImport("user32.dll")]
    private static extern bool SetClipboardData(uint uFormat, IntPtr data);

    private const uint CF_UNICODETEXT = 13;

    public static bool CopyTextToClipboard(string text)
    {
        if (!OpenClipboard(IntPtr.Zero)){
            return false;
        }

        var global = Marshal.StringToHGlobalUni(text);

        SetClipboardData(CF_UNICODETEXT, global);
        CloseClipboard();

        //-------------------------------------------
        // Not sure, but it looks like we do not need 
        // to free HGLOBAL because Clipboard is now 
        // responsible for the copied data. (?)
        //
        // Otherwise the second call will crash
        // the app with a Win32 exception 
        // inside OpenClipboard() function
        //-------------------------------------------
        // Marshal.FreeHGlobal(global);

        return true;
    }
}

Cela m’arrive dans mon application WPF. J'ai échoué à OpenClipboard (exception de HRESULT: 0x800401D0 (CLIPBRD_E_CANT_OPEN)).

j'utilise

ApplicationCommands.Copy.Execute(null, myDataGrid);

La solution est de vider le presse-papiers en premier

Clipboard.Clear();
ApplicationCommands.Copy.Execute(null, myDataGrid);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top