2010-09-24 5 views
1

Je tente de charger une simple DLL compilée avec GCC dans cygwin dans une application C# .NET. La DLL ressemble à ceciÉchec étrange lors du chargement d'une DLL C compilée avec GCC dans cygwin dans une application C# .NET

#ifndef __FOO_H 
#define __FOO_H 

#if _WIN32 
    #define EXPORT extern "C" __declspec(dllexport) 
#else //__GNUC__ >= 4 
    #define EXPORT extern "C" __attribute__((visibility("default"))) 
#endif 

EXPORT int bar(); 

#endif // __FOO_H 

La barre de fonction() retourne juste 42.

Je compilé et Linked la DLL avec

g++ -shared -o foo.dll foo.cpp 

Maintenant, je veux charger cette DLL super simple en Application C# WinForms.

public partial class Form1 : Form 
{ 
    [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] 
    static extern IntPtr GetProcAddress(IntPtr hModule, string procName); 

    [DllImport("kernel32", SetLastError = true)] 
    static extern IntPtr LoadLibrary(string lpFileName); 

    public delegate IntPtr Action2(); 

    unsafe public Form1() 
    { 
    InitializeComponent(); 

    IntPtr pcygwin = LoadLibrary("cygwin1.dll"); 
    IntPtr pcyginit = GetProcAddress(pcygwin, "cygwin_dll_init"); 
    Action init = (Action)Marshal.GetDelegateForFunctionPointer(pcyginit, typeof(Action)); 
    init(); 
    } 

    unsafe private void button1_Click(object sender, EventArgs e) 
    { 
    IntPtr foo = LoadLibrary("foo.dll");   // CRASH ... sometimes 
    IntPtr barProc = GetProcAddress(foo, "bar"); 
    Action2 barAction = (Action2)Marshal.GetDelegateForFunctionPointer(barProc, typeof(Action2)); 
    IntPtr inst = barAction(); 
    } 
} 

Maintenant, la chose étrange est: parfois cela fonctionne et parfois non. Lorsque cela ne fonctionne pas, il se bloque quand il charge foo.dll. Je l'exécute en mode débogage mais je ne reçois même pas d'exception. Le débogueur s'arrête juste comme si je l'ai arrêté moi-même!

J'ai également essayé de charger foo.dll dans le même cadre de pile où je charge cygwin1.dll. Même chose!

Des indices sur les raisons pour lesquelles cela se produit et sur ce que je peux faire pour le faire fonctionner?

Mise à jour 1: Nous utilisons les dernières Cygwin et Visual Studio 2010.

Mise à jour 2: Une hypothèse est qu'il doit avec le calendrier et la collecte des ordures. Il me semble que le temps entre le chargement de cygwin1.dll et le chargement de foo.dll est important. Plus le temps entre les deux appels LoadLibrary est court, plus il semble probable que cela fonctionne.

Mise à jour 3: Si foo.dll réussit la première fois, il réussit toujours pendant une session. Je peux cliquer sur button1 aussi souvent que je le veux.

Remarque: LoadLibrary ("foo.dll") n'échoue pas simplement pour charger foo.dll. Ce serait bien. Je se bloque et le débogueur cesse de fonctionner. Pas même une exception est levée. ET il ne plante pas toujours. Parfois ça marche!

Répondre

1

Regardez la partie "MISE À JOUR" de mon old answer sur le problème de fermeture. Je vous recommande de compiler votre DLL en respectant les outils MinGW au lieu des outils CygWin. Si rien n'est changé dans le depuis le temps l'exigence "Assurez-vous que vous avez 4K d'espace de travail au fond de votre pile" rend CygWin DLLs incompatible avec .NET. Je ne sais pas comment réaliser l'exigence dans une application .NET.

+0

Nous devons utiliser cygwin. Nous voulons compiler un client Hadoop ZooKeeper sur Windows. L'interface de ZooKeeper C dépend de cygwin dans Windows. –

+0

Et pourquoi ça marche parfois? N'est-ce pas étrange? –

+0

@Fair Dinkum Thinkum: Alors dans votre cas, il sera plus facile d'écrire un EXE au lieu de DLL et de communiquer avec l'EXE en ce qui concerne toutes les méthodes connues (pour recommander une méthode, j'ai besoin de plus d'informations). Il me semble être beaucoup plus facile que d'essayer de résoudre le problème avec l'exigence "4K d'espace de travail au fond de votre pile". – Oleg

0

Vous devriez essayer le moniteur de processus de msft. Cela est probablement dû à un échec de chargement d'une DLL dépendante. Le moniteur de processus vous montrera ce que dll et pourquoi il ne charge pas.

+0

Une dépendance manquante était la première chose à laquelle je pensais. J'ai déjà vérifié s'il y a une DLL manquante. Et pourquoi ça marche parfois? Ne devrait-il pas échouer toujours s'il manque une DLL? –

+0

Les Dll ne sont pas censées faire un travail réel dans leur DLLMain, donc une pratique courante consiste à générer un thread pour faire quelque chose. Si la prochaine DLL dépend de ce que vous faites, la charge échouera. Dans ce cas, la première DLL est probablement en train de faire quelque chose qui met à jour ou modifie le chemin pour inclure les DLL cygwin. Si tel est le cas, vous devriez pouvoir corriger les plantages en modifiant vous-même le chemin. Vous seriez en mesure de dire si c'est le cas en utilisant le moniteur de processus sur un cas de travail et d'échec et en comparant les chemins de recherche utilisés. – Mike

0

Effectuez les opérations suivantes ...

[DllImport("kernel32", CharSet=CharSet.Unicode)] 
    static extern IntPtr LoadLibrary(string lpLibFileName); 

peut-être même utiliser

[DllImport("kernel32", CharSet=CharSet.Unicode, SetLastError=true)] 

et vérifier les valeurs de retour des deux appels à LoadLibrary et GetProcAddress avant d'essayer de les utiliser.

+0

si le chargement de foo.dll se bloque, il n'y a pas de valeur de retour. C'est l'appel à LoadLibrary ("foo.dll") qui provoque le crash parfois. Parfois cela fonctionne. –

+0

@Fair, l'idée derrière ma suggestion est que la première LoadLibrary pourrait être le coupable si la signature PInvoke et les données sont détraqués. De plus, est-il "sûr" requis? Évitez la sécurité si vous le pouvez. – Les

+0

Je viens de vérifier votre hypothèse. La partie cygwin init réussit à chaque fois. J'ai également supprimé le mot clé dangereux. Aucun effet. –

Questions connexes