Solved

TCHAR[] Problem

Posted on 2006-06-19
19
1,358 Views
Last Modified: 2013-12-14
I have posted below the code for a visual c++ 2005 console app that works with MAPI profiles via MAPI33.DLL (download this if you want to test code below). My problem is when szProfile (which is a TCHAR[]) is streamed in via cin >> and then passed to createProfile, only the first letter in szProfile is used for the name of the profile.

I have marked in the code below the 3 points of interest for this problem. Any ideas?

------------------ Begin Code ------------------

#include <iostream>
#include <string>
#include <windows.h>
#include <stdio.h>
#include <mapix.h>
#include <MAPITAGS.H>
#include <MAPIUTIL.H>
#include "edkmdb.h"
#include <tchar.h>

#pragma comment(lib,"mapi32.lib")

using namespace std;

bool CreateProfileWithIProfAdmin();

istream& operator>> (istream& is, wchar_t wsz[])
{
    string line;
    getline(is, line);
    int i = 0;
    for (i = 0; i < line.length(); ++i)
    {
        wsz[i] = line[i];
    }
    wsz[i] = 0;
    return is;
}

int main() {
    CreateProfileWithIProfAdmin();

    return 0;
}

bool CreateProfileWithIProfAdmin()
{
    HRESULT hRes = S_OK; // Result from MAPI calls.
    LPPROFADMIN lpProfAdmin = NULL; // Profile Admin object.
    LPSERVICEADMIN lpSvcAdmin = NULL; // Service Admin object.
    LPMAPITABLE lpMsgSvcTable = NULL; // Table to hold services.
    LPSRowSet lpSvcRows = NULL; // Rowset to hold results of table query.
    SPropValue rgval[2]; // Property structure to hold values we want to set.
    SRestriction sres; // Restriction structure.
    SPropValue SvcProps; // Property structure for restriction.
    TCHAR szProfile[80] = {0}; // String for profile name. //<<<<<<<<<<<<<<<<<<<<<<< szProfile being declared  <<<<<<<<<<<<<<<<<<<<<<<
    TCHAR szMailbox[80] = {0}; // String for mailbox name.
    TCHAR szServer[80] = {0}; // String for server name.

    // This indicates columns we want returned from HrQueryAllRows.
    enum {iSvcName, iSvcUID, cptaSvc};
    SizedSPropTagArray(cptaSvc,sptCols) = { cptaSvc, PR_SERVICE_NAME, PR_SERVICE_UID };

    // Get configuration info from user.
    cout<<"Enter name for profile: ";
    cin>>szProfile; //<<<<<<<<<<<<<<<<<<<<<<< szProfile being streamed in <<<<<<<<<<<<<<<<<<<<<<<
    cout<<"Enter Exchange mailbox name: ";
    cin>>szMailbox;
    cout<<"Enter Exchange server name: ";
    cin>>szServer;

    // Initialize MAPI.

    if (FAILED(hRes = MAPIInitialize(NULL)))
    {
        cout<<"Error initializing MAPI.";
        goto error;
    }

    // Get an IProfAdmin interface.

    if (FAILED(hRes = MAPIAdminProfiles(0, // Flags.
        &lpProfAdmin))) // Pointer to new IProfAdmin.
    {
        cout<<"Error getting IProfAdmin interface.";
        goto error;
    }

    // Create a new profile.

    if (FAILED(hRes = lpProfAdmin->CreateProfile(szProfile, //<<<<<<<<< szProfile being used to Create a profile in MAPI <<<<<<<<<<<
        NULL, // Password for profile.
        NULL, // Handle to parent window.
        NULL))) // Flags.
    {
        cout<<"Error creating profile.";
        goto error;
    }

    // Get an IMsgServiceAdmin interface off of the IProfAdmin interface.

    if (FAILED(hRes = lpProfAdmin->AdminServices(szProfile, // Profile that we want to modify.
        NULL, // Password for that profile.
        NULL, // Handle to parent window.
        0, // Flags.
        &lpSvcAdmin))) // Pointer to new IMsgServiceAdmin.
    {
        cout<<"Error getting IMsgServiceAdmin interface.";
        goto error;
    }

    // Create the new message service for Exchange.

    if (FAILED(hRes = lpSvcAdmin->CreateMsgService(L"MSEMS", // Name of service from MAPISVC.INF.
        NULL, // Display name of service.
        NULL, // Handle to parent window.
        NULL))) // Flags.
    {
        cout<<"Error creating Exchange message service.";
        goto error;
    }

    // We now need to get the entry id for the new service.
    // This can be done by getting the message service table
    // and getting the entry that corresponds to the new service.

    if (FAILED(hRes = lpSvcAdmin->GetMsgServiceTable(0, // Flags.
        &lpMsgSvcTable))) // Pointer to table.
    {
        cout<<"Error getting Message Service Table.";
        goto error;
    }

    // Set up restriction to query table.

    sres.rt = RES_CONTENT;
    sres.res.resContent.ulFuzzyLevel = FL_FULLSTRING;
    sres.res.resContent.ulPropTag = PR_SERVICE_NAME;
    sres.res.resContent.lpProp = &SvcProps;

    SvcProps.ulPropTag = PR_SERVICE_NAME;
    SvcProps.Value.lpszA = "MSEMS";

    // Query the table to get the entry for the newly created message service.

    if (FAILED(hRes = HrQueryAllRows(lpMsgSvcTable,
        (LPSPropTagArray)&sptCols,
        &sres,
        NULL,
        0,
        &lpSvcRows)))
    {
        cout<<"Error querying table for new message service.";
        goto error;
    }

    // Setup a SPropValue array for the properties you need to configure.

    // First, the server name.
    ZeroMemory((char*)&rgval[1], sizeof(SPropValue) );
    rgval[1].ulPropTag = PR_PROFILE_UNRESOLVED_SERVER;
    rgval[1].Value.lpszA = (char*)szServer;

    // Next, the mailbox name.
    ZeroMemory((char*)&rgval[0], sizeof(SPropValue) );
    rgval[0].ulPropTag = PR_PROFILE_UNRESOLVED_NAME;
    rgval[0].Value.lpszA = (char*)szMailbox;

    // Configure the message service with the above properties.

    if (FAILED(hRes = lpSvcAdmin->ConfigureMsgService(
        (LPMAPIUID)lpSvcRows->aRow->lpProps[iSvcUID].Value.bin.lpb, // Entry ID of service to configure.
        NULL, // Handle to parent window.
        0, // Flags.
        2, // Number of properties we are setting.
        rgval))) // Pointer to SPropValue array.
    {
        cout<<"Error configuring message service.";
        goto error;
    }

    goto cleanup;

error:
    cout<<" hRes = 0x"<<hex<<hRes<<dec<<endl;
    return FALSE;

cleanup:
    // Clean up.
    if (lpSvcRows) FreeProws(lpSvcRows);
    if (lpMsgSvcTable) lpMsgSvcTable->Release();
    if (lpSvcAdmin) lpSvcAdmin->Release();
    if (lpProfAdmin) lpProfAdmin->Release();

    MAPIUninitialize();
    return TRUE;

}

------------------ End Code ------------------
0
Comment
Question by:inviser
19 Comments
 
LVL 86

Expert Comment

by:jkr
Comment Utility
Use 'wcin' four unicode input. If you had used the code I posted in your last question, it would have worked 'as is'. Or just add

#ifdef UNICODE
#define cout wcout
#define cin wcin
#endif

right after

using namespace std;

if you do not want to distinguish between these cases manually.
0
 
LVL 48

Expert Comment

by:AlexFM
Comment Utility
Add MAPI_UNICODE to Flags parameter of CreateProfile function:

    if (FAILED(hRes = lpProfAdmin->CreateProfile(szProfile,
        NULL, // Password for profile.
        NULL, // Handle to parent window.
        MAPI_UNICODE))) // Flags.
0
 
LVL 6

Author Comment

by:inviser
Comment Utility
AlexFM, when I add the MAPI_UNICODE flag to the function, it does not create profile at all.

jkr, I did as you said and it still only uses the first letter of szProfile.
0
 
LVL 86

Expert Comment

by:jkr
Comment Utility
>>jkr, I did as you said and it still only uses the first letter of szProfile.

I don't think so - checking that code, you should have gotten a bunch of conpiler errors ;o)

Anway, the code I posted - which you for some reason have chosen not to use - was

#define UNICODE
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <mapix.h>
#include <MAPITAGS.H>
#include <MAPIUTIL.H>
#include "edkmdb.h"
#include <tchar.h>

#pragma comment(lib,"mapi32.lib")

#ifdef UNICODE
#define cout wcout
#define cin wcin
#endif

using namespace std;

bool CreateProfileWithIProfAdmin();

int main() {
    CreateProfileWithIProfAdmin();

    return 0;
}

bool CreateProfileWithIProfAdmin()
{
    HRESULT hRes = S_OK; // Result from MAPI calls.
    LPPROFADMIN lpProfAdmin = NULL; // Profile Admin object.
    LPSERVICEADMIN lpSvcAdmin = NULL; // Service Admin object.
    LPMAPITABLE lpMsgSvcTable = NULL; // Table to hold services.
    LPSRowSet lpSvcRows = NULL; // Rowset to hold results of table query.
    SPropValue rgval[2]; // Property structure to hold values we want to set.
    SRestriction sres; // Restriction structure.
    SPropValue SvcProps; // Property structure for restriction.
    TCHAR szProfile[80] = {0}; // String for profile name.
    TCHAR szMailbox[80] = {0}; // String for mailbox name.
    TCHAR szServer[80] = {0}; // String for server name.

    // This indicates columns we want returned from HrQueryAllRows.
    enum {iSvcName, iSvcUID, cptaSvc};
    SizedSPropTagArray(cptaSvc,sptCols) = { cptaSvc, PR_SERVICE_NAME, PR_SERVICE_UID };

    // Get configuration info from user.
    cout<<_T("Enter name for profile: ");
    cin>>szProfile;
    cout<<_T("Enter Exchange mailbox name: ");
    cin>>szMailbox;
    cout<<_T("Enter Exchange server name: ");
    cin>>szServer;

    // Initialize MAPI.

    if (FAILED(hRes = MAPIInitialize(NULL)))
    {
        cout<<_T("Error initializing MAPI.");
        goto error;
    }

    // Get an IProfAdmin interface.

    if (FAILED(hRes = MAPIAdminProfiles(0, // Flags.
        &lpProfAdmin))) // Pointer to new IProfAdmin.
    {
        cout<<_T("Error getting IProfAdmin interface.");
        goto error;
    }

    // Create a new profile.

    if (FAILED(hRes = lpProfAdmin->CreateProfile(szProfile, // Name of new profile.      <<<<<<<<< ERROR occurs here <<<<<<<<<<<
        NULL, // Password for profile.
        NULL, // Handle to parent window.
        NULL))) // Flags.
    {
        cout<<_T("Error creating profile.");
        goto error;
    }

    // Get an IMsgServiceAdmin interface off of the IProfAdmin interface.

    if (FAILED(hRes = lpProfAdmin->AdminServices(szProfile, // Profile that we want to modify.
        NULL, // Password for that profile.
        NULL, // Handle to parent window.
        0, // Flags.
        &lpSvcAdmin))) // Pointer to new IMsgServiceAdmin.
    {
        cout<<_T("Error getting IMsgServiceAdmin interface.");
        goto error;
    }

    // Create the new message service for Exchange.

    if (FAILED(hRes = lpSvcAdmin->CreateMsgService(TEXT("MSEMS"), // Name of service from MAPISVC.INF.
        NULL, // Display name of service.
        NULL, // Handle to parent window.
        NULL))) // Flags.
    {
        cout<<_T("Error creating Exchange message service.");
        goto error;
    }

    // We now need to get the entry id for the new service.
    // This can be done by getting the message service table
    // and getting the entry that corresponds to the new service.

    if (FAILED(hRes = lpSvcAdmin->GetMsgServiceTable(0, // Flags.
        &lpMsgSvcTable))) // Pointer to table.
    {
        cout<<_T("Error getting Message Service Table.");
        goto error;
    }

    // Set up restriction to query table.

    sres.rt = RES_CONTENT;
    sres.res.resContent.ulFuzzyLevel = FL_FULLSTRING;
    sres.res.resContent.ulPropTag = PR_SERVICE_NAME;
    sres.res.resContent.lpProp = &SvcProps;

    SvcProps.ulPropTag = PR_SERVICE_NAME;
    SvcProps.Value.lpszA = _T("MSEMS");

    // Query the table to get the entry for the newly created message service.

    if (FAILED(hRes = HrQueryAllRows(lpMsgSvcTable,
        (LPSPropTagArray)&sptCols,
        &sres,
        NULL,
        0,
        &lpSvcRows)))
    {
        cout<<"Error querying table for new message service.";
        goto error;
    }

    // Setup a SPropValue array for the properties you need to configure.

    // First, the server name.
    ZeroMemory(&rgval[1], sizeof(SPropValue) );
    rgval[1].ulPropTag = PR_PROFILE_UNRESOLVED_SERVER;
    rgval[1].Value.lpszW = szServer;

    // Next, the mailbox name.
    ZeroMemory(&rgval[0], sizeof(SPropValue) );
    rgval[0].ulPropTag = PR_PROFILE_UNRESOLVED_NAME;
    rgval[0].Value.lpszW = szMailbox;

    // Configure the message service with the above properties.

    if (FAILED(hRes = lpSvcAdmin->ConfigureMsgService(
        (LPMAPIUID)lpSvcRows->aRow->lpProps[iSvcUID].Value.bin.lpb, // Entry ID of service to configure.
        NULL, // Handle to parent window.
        0, // Flags.
        2, // Number of properties we are setting.
        rgval))) // Pointer to SPropValue array.
    {
        cout<<_T("Error configuring message service.");
        goto error;
    }

    goto cleanup;

error:
    cout<<_T(" hRes = 0x")<<hex<<hRes<<dec<<endl;
    return FALSE;

cleanup:
    // Clean up.
    if (lpSvcRows) FreeProws(lpSvcRows);
    if (lpMsgSvcTable) lpMsgSvcTable->Release();
    if (lpSvcAdmin) lpSvcAdmin->Release();
    if (lpProfAdmin) lpProfAdmin->Release();

    MAPIUninitialize();
    return TRUE;

}

This should work.
0
 
LVL 6

Author Comment

by:inviser
Comment Utility
well, it pains me to say that it is still not working
0
 
LVL 86

Expert Comment

by:jkr
Comment Utility
You copied and compiled the whole thing?
0
 
LVL 6

Author Comment

by:inviser
Comment Utility
yes, maybe our environments differ?
0
 
LVL 86

Expert Comment

by:jkr
Comment Utility
That's well possible. OK, I've taken AlexFM's suggestion into account and added some output to see what profile is to be created. Could you try that?

#define UNICODE

#include <windows.h>
#include <tchar.h>

//#include <stdio.h>
#include <mapix.h>
#include <MAPITAGS.H>
#include <MAPIUTIL.H>
#include "edkmdb.h"

#include <iostream>
using namespace std;


#pragma comment(lib,"mapi32.lib")

#ifdef UNICODE
#define tcout wcout
#define tcin wcin
#else
#define tcout cout
#define tcin cin
#endif


bool CreateProfileWithIProfAdmin();

int main() {
    CreateProfileWithIProfAdmin();

    return 0;
}

bool CreateProfileWithIProfAdmin()
{
    HRESULT hRes = S_OK; // Result from MAPI calls.
    LPPROFADMIN lpProfAdmin = NULL; // Profile Admin object.
    LPSERVICEADMIN lpSvcAdmin = NULL; // Service Admin object.
    LPMAPITABLE lpMsgSvcTable = NULL; // Table to hold services.
    LPSRowSet lpSvcRows = NULL; // Rowset to hold results of table query.
    SPropValue rgval[2]; // Property structure to hold values we want to set.
    SRestriction sres; // Restriction structure.
    SPropValue SvcProps; // Property structure for restriction.
    TCHAR szProfile[80] = {0}; // String for profile name.
    TCHAR szMailbox[80] = {0}; // String for mailbox name.
    TCHAR szServer[80] = {0}; // String for server name.

    // This indicates columns we want returned from HrQueryAllRows.
    enum {iSvcName, iSvcUID, cptaSvc};
    SizedSPropTagArray(cptaSvc,sptCols) = { cptaSvc, PR_SERVICE_NAME, PR_SERVICE_UID };

    // Get configuration info from user.
    tcout<<TEXT("Enter name for profile: ");
    tcin>>szProfile;
    tcout<<TEXT("Enter Exchange mailbox name: ");
    tcin>>szMailbox;
    tcout<<TEXT("Enter Exchange server name: ");
    tcin>>szServer;

tcout << TEXT("Profile to create: ") << szProfile << endl;

    // Initialize MAPI.

    if (FAILED(hRes = MAPIInitialize(NULL)))
    {
        tcout<<TEXT("Error initializing MAPI.");
        goto error;
    }

    // Get an IProfAdmin interface.

    if (FAILED(hRes = MAPIAdminProfiles(0, // Flags.
        &lpProfAdmin))) // Pointer to new IProfAdmin.
    {
        tcout<<TEXT("Error getting IProfAdmin interface.");
        goto error;
    }

    // Create a new profile.

    if (FAILED(hRes = lpProfAdmin->CreateProfile(szProfile, // Name of new profile.      <<<<<<<<< ERROR occurs here <<<<<<<<<<<
        NULL, // Password for profile.
        NULL, // Handle to parent window.
        MAPI_UNICODE))) // Flags.
    {
        tcout<<TEXT("Error creating profile.");
        goto error;
    }

    // Get an IMsgServiceAdmin interface off of the IProfAdmin interface.

    if (FAILED(hRes = lpProfAdmin->AdminServices(szProfile, // Profile that we want to modify.
        NULL, // Password for that profile.
        NULL, // Handle to parent window.
        0, // Flags.
        &lpSvcAdmin))) // Pointer to new IMsgServiceAdmin.
    {
        tcout<<TEXT("Error getting IMsgServiceAdmin interface.");
        goto error;
    }

    // Create the new message service for Exchange.

    if (FAILED(hRes = lpSvcAdmin->CreateMsgService(TEXT("MSEMS"), // Name of service from MAPISVC.INF.
        NULL, // Display name of service.
        NULL, // Handle to parent window.
        NULL))) // Flags.
    {
        tcout<<TEXT("Error creating Exchange message service.");
        goto error;
    }

    // We now need to get the entry id for the new service.
    // This can be done by getting the message service table
    // and getting the entry that corresponds to the new service.

    if (FAILED(hRes = lpSvcAdmin->GetMsgServiceTable(0, // Flags.
        &lpMsgSvcTable))) // Pointer to table.
    {
        tcout<<TEXT("Error getting Message Service Table.");
        goto error;
    }

    // Set up restriction to query table.

    sres.rt = RES_CONTENT;
    sres.res.resContent.ulFuzzyLevel = FL_FULLSTRING;
    sres.res.resContent.ulPropTag = PR_SERVICE_NAME;
    sres.res.resContent.lpProp = &SvcProps;

    SvcProps.ulPropTag = PR_SERVICE_NAME;
    SvcProps.Value.lpszW = TEXT("MSEMS");

    // Query the table to get the entry for the newly created message service.

    if (FAILED(hRes = HrQueryAllRows(lpMsgSvcTable,
        (LPSPropTagArray)&sptCols,
        &sres,
        NULL,
        0,
        &lpSvcRows)))
    {
        tcout<<"Error querying table for new message service.";
        goto error;
    }

    // Setup a SPropValue array for the properties you need to configure.

    // First, the server name.
    ZeroMemory(&rgval[1], sizeof(SPropValue) );
    rgval[1].ulPropTag = PR_PROFILE_UNRESOLVED_SERVER;
    rgval[1].Value.lpszW = szServer;

    // Next, the mailbox name.
    ZeroMemory(&rgval[0], sizeof(SPropValue) );
    rgval[0].ulPropTag = PR_PROFILE_UNRESOLVED_NAME;
    rgval[0].Value.lpszW = szMailbox;

    // Configure the message service with the above properties.

    if (FAILED(hRes = lpSvcAdmin->ConfigureMsgService(
        (LPMAPIUID)lpSvcRows->aRow->lpProps[iSvcUID].Value.bin.lpb, // Entry ID of service to configure.
        NULL, // Handle to parent window.
        0, // Flags.
        2, // Number of properties we are setting.
        rgval))) // Pointer to SPropValue array.
    {
        tcout<<TEXT("Error configuring message service.");
        goto error;
    }

    goto cleanup;

error:
    tcout<<TEXT(" hRes = 0x")<<hex<<hRes<<dec<<endl;
    return FALSE;

cleanup:
    // Clean up.
    if (lpSvcRows) FreeProws(lpSvcRows);
    if (lpMsgSvcTable) lpMsgSvcTable->Release();
    if (lpSvcAdmin) lpSvcAdmin->Release();
    if (lpProfAdmin) lpProfAdmin->Release();

    MAPIUninitialize();
    return TRUE;

}
0
 
LVL 6

Author Comment

by:inviser
Comment Utility
The code compiles fine, but it gives a runtime error when the profile is trying to be created.

When I remove the MAPI_UNICODE flag, the profile creates fine, but only with the first letter (back to the drawing board!)
0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 
LVL 86

Expert Comment

by:jkr
Comment Utility
What output do you get from

tcout << TEXT("Profile to create: ") << szProfile << endl;

?
0
 
LVL 6

Author Comment

by:inviser
Comment Utility
It echos the profile back correctly.
0
 
LVL 86

Expert Comment

by:jkr
Comment Utility
Which runtime error are you getting?
0
 
LVL 6

Author Comment

by:inviser
Comment Utility
----------- Console Output ---------------

Enter name for profile: new
Enter Exchange mailbox name: blewis
Enter Exchange server name: mail3
Profile to create: new
Error creating profile. hRes = 0x80040103
Press any key to continue . . .
0
 
LVL 86

Expert Comment

by:jkr
Comment Utility
That is 'MAPI_E_BAD_CHARWIDTH ((SCODE)0x80040103)' aka 'Either the MAPI_UNICODE flag was set and MAPI does not support Unicode, or MAPI_UNICODE was not set and MAPI only supports Unicode.'. Great. OK, can you try to remove the

#define UNICODE

at the top and also 'MAPI_UNICODE'?
0
 
LVL 6

Author Comment

by:inviser
Comment Utility
Doing what you say gets rid of the error, but again, the name of the profile is only the first letter of szProfile.
0
 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
Comment Utility
Hm, that's getting *really* odd.
0
 
LVL 6

Author Comment

by:inviser
Comment Utility
ya, thanks for the help though, ill give your the points and maybe you can email me your visual studio project that you have been using so I can check it out (blewis@shadowmountain.org).
0
 
LVL 86

Expert Comment

by:jkr
Comment Utility
Well, apart from what I have posted, I haven't use anything but that code above and a command line of

cl.exe code.cpp

so there's not much that I could send you via email (which, by the way, isn't allowed by the EE rules: http://www.experts-exchange.com/Community_Support/help.jsp#hi99).

Also, you might want to rethink if you really wanted to accept a comment that did not solve your problem.
0
 

Expert Comment

by:exchnerd
Comment Utility
Guys,

I am facing a similar problem but also that the ConfigureMsgService is unable to configure my new service but returns S_OK.

I have a posted a question here --
http://www.experts-exchange.com/Software/Office_Productivity/Groupware/Outlook/Q_23602157.html

Thanks,
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now