Question appel compliqué des interfaces de WAB32
- blanc
- Auteur du sujet
- Hors Ligne
- Membre senior
-
- Messages : 54
- Remerciements reçus 0
Au départ, je voulais aller vite et automatiser \"l'import\" d'un carnet d'adresse dans outlookexpress6. Depuis un script PS, on peut appeler les API de wab décrites ici msdn.microsoft.com/en-us/library/ms629437%28v=VS.85%29.aspx . Le \"do not use\" ne semble pas un obstacle. En parcourant les pages, je trouve qu'il faut d'abord appeler la fonction WABOpen pour obtenir le point d'entrée de l'interface IWABObject qui propose la méthode \"Import\". Pas simple. Et il faut renseigner 2 structures.
J'ai commencé par la partie C#. Avec le premier appel, WABOpen seul, j'arrive à compiler et il me semble que l'appel réussit (code de retour = 0).
Mais lorsque je place le code pour l'appel de la seconde API (Import), je n'arrive même pas à passer le cap de la compilation. Je ne sais pas comment déclarer la fonction \"Import\" dans le source. J'ai essayé \"extern...delegate\" comme un apprentis sorcier mais sans résultat.
Le code C# qui ne fonctionne pas avec la fonction Import :
[code:1]
using System;
using System.Runtime.InteropServices;
namespace Win32Api
{
public class OE_Wab32Utilities
{
// Wrapper for the NULL handle or pointer.
static private IntPtr NullPtr = ((IntPtr)((int)(0)));
[StructLayout(LayoutKind.Sequential)]
public struct WAB_PARAM
{
public ulong cbSize; //he size of the WAB_PARAM structure in bytes
public uint hwnd;
public IntPtr szFileName; //Value of type LPTSTR that specifies the WAB file name to open. If this parameter is NULL, the default Address Book file is opened.
public ulong ulFlags;
// ???
public ulong guidPSExt; //Value of type GUID that specifies the GUID that identifies the calling application's property sheet extensions
}
[DllImport(\"C:\\Program Files\\Fichiers communs\\System\\wab32.dll\"«»)]
public static extern uint WABOpen(
out IntPtr lppAdrBook,
out IntPtr lppWABObject,
ref WAB_PARAM lpWABParam,
long Reserved2
);
[StructLayout(LayoutKind.Sequential)]
public struct WABIMPORTPARAM
{
public ulong cbSize;
public IntPtr lpAdrBook;
public uint hwnd;
public ulong ulFlags;
public string lpszFileName;
}
//
// la fonction qui pose problème à la compilation !!!!!!
//
public static extern long Import(
ref WABIMPORTPARAM lpImportParam
);
static void Main(string[] args)
{
IntPtr lppAdrBook = NullPtr;
IntPtr lppWABObject = NullPtr;
uint iRet;
long lRet;
WAB_PARAM lpWABParam = new WAB_PARAM();
WABIMPORTPARAM lpWABImportParam = new WABIMPORTPARAM();
lpWABParam.cbSize=(ulong)Marshal.SizeOf(typeof(WAB_PARAM));
lpWABParam.hwnd=0;
//Value of type LPTSTR that specifies the WAB file name to open.
// If this parameter is NULL, the default Address Book file is opened.
lpWABParam.szFileName=NullPtr;
// Only want to deal with \"Main Identity's Contacts\"
//#define WAB_ENABLE_PROFILES 0x00400000
lpWABParam.ulFlags=0x00400000;
// WAB_LOCAL_CONTAINERS ?
// ???
lpWABParam.guidPSExt=0;
//Value of type GUID that specifies the GUID that identifies the calling application's property sheet extensions
iRet = WABOpen(out lppAdrBook, out lppWABObject, ref lpWABParam, (long)0); // PB
Console.WriteLine (iRet);
if (args.Length != 1 )
{
return ;
}
Console.WriteLine (args[0]);
// pour sizeof : ps.cbSize = Marshal.SizeOf(typeof(CRYPTPROTECT_PROMPTSTRUCT));
lpWABImportParam.cbSize=(ulong)Marshal.SizeOf(typeof(WABIMPORTPARAM));
lpWABImportParam.lpAdrBook = lppAdrBook ; // PB
lpWABImportParam.hwnd=0;
lpWABImportParam.ulFlags=0;
lpWABImportParam.lpszFileName=args[0]; //IntPr.Zero;
// pb de compilation avec la fonction Import : COMMMENT ECRIRE
lRet = lppWABObject.Import( ref lpWABImportParam );
Console.WriteLine (lRet);
}
}//fin de la class
}//fin du namespace
[/code:1]
Je débute en PS et C#. Si le code C# fonctionne, l'enrobage en PS est facile.
Il me manque peut être trop de bases en c# pour arriver à un code c# opérationnel.
Et je n'ai pas trouvé sur internet d'exemple en c# d'appel de l'api d'Import de WAB.
Si quelqu'un peut m'orienter...
Merci d'avance.
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Hors Ligne
- Modérateur
-
- Messages : 6311
- Remerciements reçus 68
si ta classe encapsule une structure externe tu dois,à l'aide d'un attribut , préciser laquelle.
noel écrit:
Tu peux déjà essayer de lire la documentation avant de coderJ'ai essayé \"extern...delegate\" comme un apprentis sorcier mais sans résultat.
Sur Google \"C# PInvoke\" te renvoi qq liens, les 5-8 premiers sont déjà suffisant pour comprendre le mécanisme, sous réserve de connaitre les API Win32 et un minimum sur le langage C.
As-tu recherché des exemples à l'aide de Google Code ?
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- blanc
- Auteur du sujet
- Hors Ligne
- Membre senior
-
- Messages : 54
- Remerciements reçus 0
C'est vrai que le mécanisme est compliqué. J'ai lu plein de \"doc\" pendant tout le weekend et heureusement qu'il fait un froid polaire. Mais je ne comprends pas tout ce que je lis.
J'ai aussi bien sûr commencé par chercher des exemples tout prêt mettant en oeuvre la méthode import de l'interface IWABObject contenu dans WAB32.dll.
Ce qui est déroutant avec cette interface, c'est qu'on l'obtient en retour de l'appel d'une fonction d'une dll.
Et du coup je ne sais pas la déclarer dans le code C#.
Je reconnais que depuis que je lis des informations sur ce sujet (P/Invoke...) j'en arrive à tout mélanger.
Si je tente d'amorcer un résumé des différentes possibilités d'accéder à des fonctions ou méthodes :
a - Le cas le plus simple, c'est l'appel d'une API win32 comme messagebox, quoique le type des paramètres reste parfois un mystère (j'ai remplacé les int et l'unsigned int par des intptr et les tableaux de char par string sinon j'avais des erreurs de compilation).
[code:1]
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
namespace SysWin32
{
public static class MonMsgBox
{
[DllImport(\"user32.dll\", EntryPoint = \"MessageBox\"«»)]
public static extern IntPtr MessageBox(IntPtr hWnd, string lpText, string lpCaption, IntPtr uType);
}
}
'@ -Language CSharp
[SysWin32.MonMsgBox]::MessageBox( 0, \"Hello world!\", \"Greetings\", 0 )
[/code:1]
J'ai tenté de faire la même chose avec :
[code:1]
[DllImport(\"comdlg32.dll\", SetLastError=true,CharSet = CharSet.Auto)]
static extern bool GetOpenFileName([In, Out] OpenFileName ofn);
[/code:1]
Et là se sont les filtres qui ne marchaient pas comme je voulais (il fallait cliquer sur \"ouvrir\" pour rafraîchir le contenu en cas de changement de filtre)
b - Le genre d'appel précédent n'est pas forcément utile car dot.net offre plein de fonctions (mais quel est le bon terme ici?) qui font la même chose.
[code:1]
[reflection.assembly]::loadwithpartialname(\"system.windows.forms\"«»)
[System.Windows.Forms.MessageBox]::«»Show(
\"Do you want to map the new printer?\",
\"Map Printer\",
[System.Windows.Forms.MessageBoxButtons]::YesNoCancel,
[System.Windows.Forms.MessageBoxIcon]::Information,
[System.Windows.Forms.MessageBoxDefaultButton]::Button3, [System.Windows.Forms.MessageBoxOptions]::«»ServiceNotification
)
[/code:1]
Sur un site, il est dit : \"Instead of using P/Invoke, you might read the documentation for the OpenFileDialog component that encapsulates that API and struct\"
c - un cas tout nouveau pour moi lu dans la question précédente :
$NLMType = [Type]::GetTypeFromCLSID(‘DCB00C01-570F-4A9B-8D69-199FDBA5723B’)
$INetworkListManager = [Activator]::CreateInstance($NLMType)
Là j'avoue que j'en ai pour un bon moment pour comprendre et je lirais la documentation sur MSDN plus attentivement que ce le simple survol d'hier. Et j'avoue que je n'arrive pas encore à grimper à l'arbre.... blogs.codes-sources.com/cyril/archive/20...ois-plus-rapide.aspx
d - les cas que je ne connais pas et qui sont nombreux
J'ai lu aussi plusieurs articles sur le code managed et unmanaged dont celui ci :
www.codeguru.com/cpp/cpp/cpp_managed/interop/article.php/c6867/
Où il est dit :\"While the .NET Interop Services offer very good support to integrate C-style DLLs and COM objects directly into your C# or VB.NET code, the same is not true for unmanaged C++ class libraries. If you want to make calls into an unmanaged C++ class library, you definitely have to write a wrapper class, and you have to write it in managed C++. \"
C'est vrai que j'ai beaucoup de mal avec les objets COM.
Pour en revenir à la méthode import de wab32.dll, je continue de chercher comment déclarer cette fonction.
J'y retourne...
Mais si vous avez une idée, merci d'avance.
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Hors Ligne
- Modérateur
-
- Messages : 6311
- Remerciements reçus 68
Ce que tu comptes réaliser semble possible.
noel écrit:
C'est normal, il faut payer de sa personne pour arriver à coder COMj'en arrive à tout mélanger.
De mon côté, je connais juste les bases.
noel écrit:
Sache que PowerShell ne sait pas gérer des interfaces \"pures\", COM ou C#.Ce qui est déroutant avec cette interface, c'est qu'on l'obtient en retour de l'appel d'une fonction d'une dll.
Il va te falloir coder un Wrapper en C# afin de pouvoir la manipuler sous PS. C'est le même pb dans ce post.
Dés que j'ai le temps je reviendrais sur les autres points.
noel écrit:
Cela concerne, entre autre, les bases de la création d'instance COM en C#.c - un cas tout nouveau pour moi lu dans la question précédente :
[code:1]
$NLMType = [Type]::GetTypeFromCLSID(‘DCB00C01-570F-4A9B-8D69-199FDBA5723B’)
$INetworkListManager = [Activator]::CreateInstance($NLMType)[/code:1]
On utilise le classID, référencé dans la registry, pour créer une instance de l'objet COM.
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- blanc
- Auteur du sujet
- Hors Ligne
- Membre senior
-
- Messages : 54
- Remerciements reçus 0
Heuuuuuu, juste les bases ?
J'ai effectivement trouvé plusieurs (mais pas trop) bouts de code en C++, en PowerBasic qui parcourent le carnet d'adresse. Mais pas un seul qui fasse un import. Mais même pour les méthodes autres que \"import\", il faut bien réaliser un appel à la fonction Wabopen qui fournit l'adresse de l'interface proposant ces méthodes. Sur cet enchaînement, je crois avoir bien compris. J'ai trouvé aussi un fichier d'include \"wabapi.h\" qui rejoint bien sûr la documentation de msdn.
J'ai aussi bien compris que je dois utiliser c# pour accéder à cet \"object\". L'enrobage PS n'est pas forcément utile. D'ailleurs pendant mes tests \"stériles\" je compile uniquement le c# avec csc.exe (en ligne de commande, c'est pas compliquée, quoique /unsafe resterait un mystère si je devais l'employer, mais bref).
J'en reviens toujours à ma déclaration de la fonction \"import\". Si seulement un \"bon vieux cast\" pouvait faire l'affaire !
Merci pour les encouragements.
Connexion ou Créer un compte pour participer à la conversation.
- blanc
- Auteur du sujet
- Hors Ligne
- Membre senior
-
- Messages : 54
- Remerciements reçus 0
C'est peut être la déclaration du point d'entrée de l'interface reçu en retour de l'appel de la fonction wabopen qui pose problème.
[code:1]
IntPtr lppWABObject = NullPtr;
...
iRet = WABOpen(out lppAdrBook, out lppWABObject, ref lpWABParam, (long)0);
[/code:1]
Car il est impossible de trouver une fonction \"import\" (ou une autre) à partir d'un simple IntPtr. C'est d'ailleurs le sens du message d'erreur du compilateur.
[code:1]lRet = lppWABObject.Import( ref lpWABImportParam );
\" error CS0117: 'System.IntPtr' ne contient pas de définition pour 'Import'\"[/code:1]
Il faudrait que je puisse déclarer que lppWABObject est une interface avec tous ses membres.
Bon, ca reste une piste. Ca me titille du côté du delegate mais je suis pas au top, loin de là.
Je vais arroser mon petit mandarinier issu d'un pépin, ca va me refaire une santé.
Bonne soirée.
Connexion ou Créer un compte pour participer à la conversation.
- Vous êtes ici :
-
Accueil
-
forum
-
PowerShell
-
Entraide pour les initiés
- appel compliqué des interfaces de WAB32