How to use 32-bit DLL in x64 environment? It won't let me force x86 compile!

4.5k views Asked by At

VC++ 2008, CLR Console App, being developed under win7 x64.

I'm using .net with MS Office v.12 PIA's to do some Excel automation, which is coming along quite nicely. But now, I'm starting the next portion of the code which involves doing some simple email transactions, so I'm trying to get MAPI working in my code. Basically, it reads the appropriate registry key to get the full path to the OLMAPI32.DLL file, and then tries to LoadLibrary/GetProcAddress from within that dll.

Here's a snippet:


using namespace System;
using namespace Microsoft::Office::Interop;
using namespace Microsoft::Win32;

int main(array<System::String ^> ^args)
{
    RegistryKey^ subK = Registry::LocalMachine->OpenSubKey("SOFTWARE\\Clients\\Mail\\Microsoft Outlook");
    String^ mailDll = safe_cast<String^>(subK->GetValue("DLLPathEx"));
    CStringW cStrMailDll = mailDll; //Just to put mailDll in a format that LoadLibrary() can read.

    LPMAPIINITIALIZE mapiInit = NULL;

    HMODULE mapiLib = LoadLibrary(cStrMailDll); // This Returns NULL
    if(mapiLib == NULL)
    {
        printf("\nError: %d\n", GetLastError()); // System Error 193 - ERROR_BAD_EXE_FORMAT
        return 1;
    }

    ...(more code)
    ...

It comes as no shock to me that LoadLibrary sets system error 193: "%1 is not a valid Win32 application." After doing some research, I figure all I need to do is force x86 compile. So I go to Configuration Manager, and under Active solution platform, my only choices are Win32, New and Edit. So I click New, type in "x86" under "Type or select the new platform", and click "Copy settings from" to select "Any CPU" or something suitable, but my only choice is Win32, and ! I figured maybe it was because I was already targeting .net, so to test that theory, I started a new project, this time as a Win32 Console App. Even under that type of project, my only choice is Win32. The x86, x64, Any CPU, and Itanium that I've heard about don't exist in my VS2008!

So I'm at a loss here. How do I force VS to compile my exe as x86 so that I can use the mapi interface? Or is there a 64-bit version of OLMAPI32.DLL that I can use? How the heck do I get MAPI working in my code if there's no 64-bit library for it and VS gives me the dear-in-the-headlights when I try to set up my environment for x86? I just can't believe that my 64-bit environment automatically disqualifies me from using MAPI.

Thanks

4

There are 4 answers

2
bryanbcook On BEST ANSWER

I believe Win32 is x86 in Visual Studio C++

3
sharptooth On

There is a 64-bit version of MAPI that comes together with 64-bit version of MS Outlook. This MSDN article describes it in details.

0
John On

You can force 32-bit CLR by usihg corflags. e.g. CorFlags.exe /32bit+ file.exe

0
Pleonasm On

So, for the edification of those who helped me, as well as any who may have similar issues and happen upon this thread, here's what I ended up doing...

I chickened-out of the pure MAPI route and decided to go through the Outlook PIA instead. So now my code looks like this:

#define nul Reflection::Missing::Value
#include "stdafx.h"
using namespace System;
using namespace Microsoft::Office::Interop;

int main(array<System::String ^> ^args)
{
    // Create the outlook object
    Outlook::Application^ olApp = gcnew Outlook::Application();

    // Get an instance of the MAPI namespace via the outlook object
    Outlook::NameSpace^ olNs = olApp->GetNamespace("MAPI");

    // Log this instance into the MAPI interface
    // Note that this will cause the user to be prompted for which profile
    // to use. At least, it prompts me, and I only have one profile anyway. Whatever.
    // Change the first argument to the name of the profile you want it to use (String)
    // to bypass this prompt. I personally have mine set to "Outlook".
    olNs->Logon(nul, nul, true, true);

    // Get my Inbox
    Outlook::Folder^ defFolder = safe_cast<Outlook::Folder^>(olNs->GetDefaultFolder(Outlook::OlDefaultFolders::olFolderInbox));

    // Get all of the items in the folder (messages, meeting notices, etc.)
    Outlook::Items^ fItems = defFolder->Items;

    // Sort them according to when they were received, descending order (most recent first)
    fItems->Sort("[ReceivedTime]", true);

    // Show me the folder name, and how many items are in it
    printf("\n%s: %d\n", defFolder->Name, fItems->Count);

    // Make an array of _MailItems to hold the messages.
    // Note that this is a _MailItem array, so it will only hold email messages.
    // Other item types (in my case, meeting notices) cannot be added to this array.
    array<Outlook::_MailItem^>^ mail = gcnew array<Outlook::_MailItem^>(fItems->Count);

    int itemNum = 1;
    int offset = 0;

    // If there's anything in my Inbox, do the following...
    if(fItems->Count)
    {
        // Try to grab the first email with "fItems->GetFirst()", and increment itemNum.
        try
        {
            mail[itemNum++] = safe_cast<Outlook::_MailItem^>(fItems->GetFirst());
        }
        // If it threw an exception, it's probably because the item isn't a _MailItem type.
        // Since nothing got assigned to mail[1], reset itemNum to 1
        catch(Exception^ eResult)
        {
            itemNum = 1;
        }

        // Ok, now use "fItems->GetNext()" to grab the rest of the messages
        for(; itemNum <= (fItems->Count-offset); itemNum++)
        {
            try
            {
                mail[itemNum] = safe_cast<Outlook::_MailItem^>(fItems->GetNext());
            }
            // If it puked, then nothing got assigned to mail[itemNum]. On the next iteration of
            // this for-loop, itemNum will be incremented, which means that *this* particular index
            // of the mail array would be left empty. To prevent this, decrement itemNum.
            // Also, if itemNum ever gets decremented, then that will ultimately cause this loop
            // to iterate more times than fItems->Count, causing an out-of-bounds error. To prevent
            // that, increment "offset" each time you decrement "itemNum" to compensate for the
            // offset.
            catch(Exception^ eResult)
            {
                itemNum--;
                offset++;
            }
        }

        // Show me the money!
        for(int i=1; i <= (fItems->Count-offset); i++)
            printf("%d - %s\n", i, mail[i]->Subject);
    }

    olNs->Logoff();
    return 0;
}

Now that I know how to get in, I can go ahead and finish my project! Thanks for all the help, everyone!

Cheers! d