Question appel compliqué des interfaces de WAB32

Plus d'informations
il y a 15 ans 3 mois #8367 par blanc
bonjour,
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.

Plus d'informations
il y a 15 ans 3 mois #8369 par Laurent Dardenne
Salut,
si ta classe encapsule une structure externe tu dois,à l'aide d'un attribut , préciser laquelle.
noel écrit:

J'ai essayé \"extern...delegate\" comme un apprentis sorcier mais sans résultat.

Tu peux déjà essayer de lire la documentation avant de coder ;)
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.

Plus d'informations
il y a 15 ans 3 mois #8370 par blanc
Bonjour,
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.

Plus d'informations
il y a 15 ans 3 mois #8386 par Laurent Dardenne
Je n'ai pas trop cde temps à te consacrer sur ce sujet, mais je pense que tu vas plus vite que la musique.
Ce que tu comptes réaliser semble possible.
noel écrit:

j'en arrive à tout mélanger.

C'est normal, il faut payer de sa personne pour arriver à coder COM :silly:.
De mon côté, je connais juste les bases.
noel écrit:

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.

Sache que PowerShell ne sait pas gérer des interfaces \"pures\", COM ou C#.
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:

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]

Cela concerne, entre autre, les bases de la création d'instance COM en C#.
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.

Plus d'informations
il y a 15 ans 3 mois #8387 par blanc
Bonsoir,

Heuuuuuu, juste les bases ? :woohoo: Moi, je m'en contenterais bien de ces 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.

Plus d'informations
il y a 15 ans 3 mois #8388 par blanc
re bonsoir,
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.

Temps de génération de la page : 0.077 secondes
Propulsé par Kunena