Using HD COM macros for accessing MAPI functions 
Author Message
 Using HD COM macros for accessing MAPI functions

I'm trying to figure out how/if I can use HD to do some MAPI (Messaging API)
programming.  I'm not a COM or OLE expert.   However,  it appears from my
reading so far that MAPI is constructed basically like a COM interface
except that the interfaces and objects are manually coded for the C-based
API.  That is, the objects have vtable interfaces.  Object inheritance is
achieved manually (in the C interfaces) by building up object definitions
through some rather ugly C macro definitions.  This may be an
oversimplification, but that's what I get by looking at the mapidefs.h
header file and the MAPI help in the SDK documentation.

There are 4 different standard APIs to use for MAPI: OLE messaging, CMC,
simple MAPI, and full MAPI.   Because of what I want to do, I think I need
to use full MAPI.

HERE'S MY QUESTION IN A NUTSHELL:
Is it possible to use one of the HD interface-defining DYLAN macros to
create a Dylan lookalike to a MAPI object like the IABContainer #defined in
the header code below?

I'm thinking that one of the macros like "define custom-interface" or
"define vtable-interface" could be used.  It seems like one or more of these
macros ought to come close to doing the job, but there may be some holes.
For example, I don't have a GUID, and I would certainly have to define C-FFI
versions of all interface methods, such as CopyEntries show below.

/* THIS IS TAKEN FROM MAPIDEFS.H */
#define MAPI_IABCONTAINER_METHODS(IPURE)                                \
    MAPIMETHOD(Crea{*filter*}try)                                             \
        (THIS_  ULONG                       cbEntryID,                  \
                LPENTRYID                   lpEntryID,                  \
                ULONG                       ulCreateFlags,              \
                LPMAPIPROP FAR  *           lppMAPIPropEntry) IPURE;    \
    MAPIMETHOD(CopyEntries)                                             \
        (THIS_  LPENTRYLIST                 lpEntries,                  \
                ULONG                       ulUIParam,                  \
                LPMAPIPROGRESS              lpProgress,                 \
                ULONG                       ulFlags) IPURE;             \
    MAPIMETHOD(Dele{*filter*}tries)                                           \
        (THIS_  LPENTRYLIST                 lpEntries,                  \
                ULONG                       ulFlags) IPURE;             \
    MAPIMETHOD(ResolveNames)                                            \
        (THIS_  LPSPropTagArray             lpPropTagArray,             \
                ULONG                       ulFlags,                    \
                LPADRLIST                   lpAdrList,                  \
                LPFlagList                  lpFlagList) IPURE;          \

#undef       INTERFACE
#define      INTERFACE  IABContainer
DECLARE_MAPI_INTERFACE_(IABContainer, IMAPIContainer)
{
    BEGIN_INTERFACE
    MAPI_IUNKNOWN_METHODS(PURE)
    MAPI_IMAPIPROP_METHODS(PURE)
    MAPI_IMAPICONTAINER_METHODS(PURE)
    MAPI_IABCONTAINER_METHODS(PURE)

Quote:
};



Tue, 25 Dec 2001 03:00:00 GMT  
 Using HD COM macros for accessing MAPI functions

Quote:

> Is it possible to use one of the HD interface-defining DYLAN macros
> to create a Dylan lookalike to a MAPI object like the IABContainer
> #defined in the header code below?

Yes, I think so. From what I understand of MAPI it is all done through
COM objects. I can't find a type library for these objects but it is
all defined in the header file(s) you mention in that wonderfully
obfuscated manner that allows calling the MAPI objects through both C
and C++.

Quote:
> I'm thinking that one of the macros like "define custom-interface"
> or "define vtable-interface" could be used.

I think you are right. I'm no expert in the HD COM macros
however. You'll have to come up with definitions and macros to wrap
all the interfaces you want to use from the MAPI header files.

I'll show a quick example of how I use the HD COM macros to access a
custom COM component written in C++ where you don't have the type
library for that component (otherwise it would much easier using the
HD support for type libraries).

I wrote a simple C++ COM object with the following interface:

        [
                object,
                uuid(663AC96D-3701-11D3-BD70-AFE39D96FD61),

                helpstring("IHelloCPP Interface"),
                pointer_default(unique)
        ]
        interface IHelloCPP : IUnknown
        {
                HRESULT SayHello([in] int times);
        };

Given a pointer to an object that implements this interface, calling
SayHello(5) should display some hello type message 5 times. The C++
coclass that implements this interface looked like:

        [
                uuid(663AC96E-3701-11D3-BD70-AFE39D96FD61),
                helpstring("HelloCPP Class")
        ]
        coclass HelloCPP
        {
                [default] interface IHelloCPP;
        };

In Dylan I used the custom-interface macro to create the wrapper for
IHelloCPP:

  define constant $hello-interface-id =
    "{663AC96D-3701-11D3-BD70-AFE39D96FD61}";
  define constant $hello-class-id =
    "{663AC96E-3701-11D3-BD70-AFE39D96FD61}";

  define custom-interface <IHelloCPP> (<IUnknown>)
    client-class <hello-client>;
    uuid $hello-interface-id;

    function say-hello( times :: <integer>) => ();
  end custom-interface <IHelloCPP>;

Note that I did not need to include the HRESULT return code for
SayHello. This is automatically assumed by the custom-interface
macro. The 'client-class' is the name of the class that I'll use for
calling the methods of IHelloCPP. I'm not entirely sure about it's use
and difference from <IHelloCPP>, all I know is it is needed.

Now to create an instance of the C++ server object and access it
through the IHelloCPP interface, I use the following code:

  with-COM-interface (hello :: <hello-client> = $hello-class-id,
                      interface-id: $hello-interface-id)
    say-hello(hello, 4);
  end;

I was surprised how little code was actually required to do it. I like
Dylan :-).

With the MAPI interfaces you will need to do custom-interface
definitions for the ones you want to use - and the ones that they
use. For example, the code you provided from the header file:

Quote:
> DECLARE_MAPI_INTERFACE_(IABContainer, IMAPIContainer)
> {
>     BEGIN_INTERFACE
>     MAPI_IUNKNOWN_METHODS(PURE)
>     MAPI_IMAPIPROP_METHODS(PURE)
>     MAPI_IMAPICONTAINER_METHODS(PURE)
>     MAPI_IABCONTAINER_METHODS(PURE)
> };

This would be something like the following in IDL:

        interface IMAPIProp : IUnknown
        {
                // IMAPIProp methods
        };

        interface IMAPIContainer : IMAPIProp
        {
                // IMAPIContainer methods
        };

        interface IABContainer : IMAPIContainer
        {
                // IABContainer methods
        };

So you'll need to find the IID's for all those interfaces (from
mapiguid.h) and do something like:

  define custom-interface <IMAPIProp> (<IUnknown>)
    client-class <IMAPIProp-client>;
    uuid $IID-IMAPIProp;

    // methods
  end custom-interface <IMAPIProp>;

  define custom-interface <IMAPIContainer> (<IMAPIProp>)
    client-class <IMAPIContainer-client>;
    uuid $IID-IMAPIContainer;

    // methods
  end custom-interface <IMAPIContainer>;

And so on. Once that is done you should be able to use the MAPI stuff
without too many problems....I think. Apart from the hello client
stuff above, the rest is untested - I haven't actually tried calling
any of the MAPI routines but I have called other COM routines using
this approach.

Quote:
> For example, I don't have a GUID

You should have GUID's for the interfaces and the objects. Or at
least, an object that you create that is used to create instances of
the other objects.

Quote:
>I would certainly have to define C-FFI versions of all interface
>methods, such as CopyEntries show below.

Here is an example of what I think CopyEntries would probably look
like in your custom-interface:

The C code:

Quote:
>     MAPIMETHOD(CopyEntries)                                             \
>         (THIS_  LPENTRYLIST                 lpEntries,                  \
>                 ULONG                       ulUIParam,                  \
>                 LPMAPIPROGRESS              lpProgress,                 \
>                 ULONG                       ulFlags) IPURE;

The Dylan code:

  define custom-interface <IABContainer> (<IMAPIContainer>)
    client-class <IABContainer-client>;
    uuid $IID-IABContainer;

    // The methods from MAPI_IABCONTAINER_METHODS
    function copy-entries(
      lpEntries :: <LPENTRYLIST>,
      ulUIParam :: <ULONG>,
      lpProgress :: <LPMAPIPROGRESS>,
      ulFlags :: <ULONG) => ();

    // The rest of the methods...

  end custom-interface <IMAPIContainer>;

You probably won't want to use methods names like 'copy-entries'. You
might want to follow similar naming standards to that used by
Harlequin, in which case the method name will be
'IABContainer/CopyEntries'.

All of the above was done using Harlequin Dylan 2.0 beta 2. Some of
the macros may not exist or may be different in HD 1.2 - I'm not sure.

I hope some of that helps. Any questions, comments, suggestions,
please let me know.

Chris.



Wed, 26 Dec 2001 03:00:00 GMT  
 
 [ 2 post ] 

 Relevant Pages 

1. Problems using MAPI to access Notes mail database

2. Using MAPI functions in Clarion 4

3. Problem accessing the COM port using Causeway

4. accessing COM ports using FPS4.0

5. MAPI/COM: where is the server?

6. link to direct floppy/hd access?

7. Accessing HD via DMA

8. How do you access DLL functions using Regina REXX under Windows NT

9. Sending e-mail using MAPI

10. Sending Mail from MF/NetExpress Object COBOL using MAPI services

11. Q: Is there any good documentation on MAPI using Python

 

 
Powered by phpBB® Forum Software