Category: Microsoft
Category Archives: Microsoft
Image Gallery
Hi
I am making a powerapp connected to sharepoint.
I want to use images, stored on sharepoint.
First i wanted to use the APP Picture gallery, but I can see this function will no longer be available end this month.
I can use a Sharepointlist with an image column, but it will take long time to create and maintain.
Is there any other way to easy drag and drop pictures to sharepoint?
Tony
Hi I am making a powerapp connected to sharepoint. I want to use images, stored on sharepoint. First i wanted to use the APP Picture gallery, but I can see this function will no longer be available end this month. I can use a Sharepointlist with an image column, but it will take long time to create and maintain. Is there any other way to easy drag and drop pictures to sharepoint? Tony Read More
When SharePoint page is promoted to Viva Engage, Viva Connection web part not showing all content
Page is promoted to Viva Engage and in Viva Engage the post is there.
When its picked up by Viva Connections web part on our home page. The entry doesn’t show the content, the thumbnail image, title and description aren’t showing.
Page is promoted to Viva Engage and in Viva Engage the post is there.When its picked up by Viva Connections web part on our home page. The entry doesn’t show the content, the thumbnail image, title and description aren’t showing. Read More
How to customize permissions
I am trying to find a way to restrict the permissions a team of users has in my Azure Board in order for them to only be able to:
Create new work itemsWrite comments in the discussionAdd/delete attachments
I want no moving of the cards/rank stack, no assigning, no creating tags, etc.
This group right now has Stakeholder access but I usually find them moving cards between swimlanes (even if by mistake) which messes up the rules and automations in place.
I’ve tried some different permissions but can’t get to the needed level of restriction.
Is there a way to do this?
Thank you.
I am trying to find a way to restrict the permissions a team of users has in my Azure Board in order for them to only be able to:Create new work itemsWrite comments in the discussionAdd/delete attachmentsI want no moving of the cards/rank stack, no assigning, no creating tags, etc.This group right now has Stakeholder access but I usually find them moving cards between swimlanes (even if by mistake) which messes up the rules and automations in place.I’ve tried some different permissions but can’t get to the needed level of restriction. Is there a way to do this? Thank you. Read More
Why is View My Paycheck Not Working?
I’ve been trying to access my paycheck details through the “View My Paycheck” portal, but it isn’t working. I’ve checked my internet connection and tried different browsers, but nothing seems to help. The page either doesn’t load or shows an error message. What could be causing this issue, and how can I resolve it?
I’ve been trying to access my paycheck details through the “View My Paycheck” portal, but it isn’t working. I’ve checked my internet connection and tried different browsers, but nothing seems to help. The page either doesn’t load or shows an error message. What could be causing this issue, and how can I resolve it? Read More
What Could be the Reason for Workforce Not Displaying Paystubs?
I’ve been trying to access my paystubs on the Workforce platform, but they’re not showing up. Despite logging in multiple times and navigating through the platform, I can’t seem to find my paystub information. I’ve checked my account settings and ensured that I’m accessing the correct portal, but the issue persists. Can you help me understand why my paystubs aren’t appearing on the Workforce platform and what steps I can take to resolve this?
I’ve been trying to access my paystubs on the Workforce platform, but they’re not showing up. Despite logging in multiple times and navigating through the platform, I can’t seem to find my paystub information. I’ve checked my account settings and ensured that I’m accessing the correct portal, but the issue persists. Can you help me understand why my paystubs aren’t appearing on the Workforce platform and what steps I can take to resolve this? Read More
How to insert equation in Microsoft Publisher?
Hello dear experts,
If is there any one who can help me to solve the problem of inserting equation in Microsoft Publisher?
I have tried to add an object named the Microsoft Equation 3.0, but there is not seen such thing in that.
Hello dear experts,If is there any one who can help me to solve the problem of inserting equation in Microsoft Publisher?I have tried to add an object named the Microsoft Equation 3.0, but there is not seen such thing in that. Read More
Why Is Workforce Not Showing Paystub?
I’ve been attempting to access my paystub on the Workforce platform, but it’s not displaying. Despite logging in and navigating through the platform, I can’t seem to find any information regarding my paystub. I’ve checked my account settings and verified that I’m accessing the correct portal, but the issue persists. Can you help me understand why my paystub isn’t showing up on the Workforce platform and provide guidance on how to resolve this?
I’ve been attempting to access my paystub on the Workforce platform, but it’s not displaying. Despite logging in and navigating through the platform, I can’t seem to find any information regarding my paystub. I’ve checked my account settings and verified that I’m accessing the correct portal, but the issue persists. Can you help me understand why my paystub isn’t showing up on the Workforce platform and provide guidance on how to resolve this? Read More
Value Base Delivery (VBD) to accelerate GenAI use case implementation
Exploring Generative AI Solutions: A Customer-Centric Approach
When faced with specific challenges, customers often seek Generative AI solutions. These solutions, while powerful, come with inherent complexity. They involve integrating diverse data sources, augmenting data, automating business processes, and gathering input from end users. To successfully implement such solutions and leverage publicly available Accelerators, users must possess technical expertise, allocate sufficient time for implementation, and adhere to best practices. Additionally, they need to carefully evaluate which solution aligns with their unique issue.
Microsoft recognizes these challenges and has developed a series of Value-Based Deliveries (VBDs). These meticulously tailored VBDs address customer needs while adhering to industry best practices. During Value-Based Deliveries, customers learn while entrusting the intricate aspects and acceleration process of Generative AI solutions to Microsoft. In this blog, we will delve into an explanation of Accelerators and VBDs.
Accelerators & Value-Based Deliveries:
Accelerators: Customers have the right to use openly available accelerators to build their own solutions. However, this standardized technique may not always fit every customer scenario. Adjusting the accelerator requires expertise, and customers must have highly trained personnel to work on it.
Value-Based Delivery (VBD): VBD is a customer-focused approach to software development. It provides 24/7 as-needed problem-solving with critical incident escalation, ensuring that Microsoft’s services align with the customer’s needs. VBDs prioritize creating software that directly contributes to business value and aligns with organizational goals. While accelerators can support VBDs, using accelerators alone resembles a QuickStart, template, or architectural reference—not a fully built solution.
A team of trusted advisors, led by Microsoft Subject Matter Experts (SMEs), provides thorough guidance and developer support to accelerate business outcomes. VBDs are designed programs tailored to customers’ development needs and business goals. They leverage proven tools, best practices, and deep technical expertise to create high-value and positive outcomes for customer use cases. With direct, high-level assistance at each stage of the development life cycle, customers can establish consistent methodologies, progress competitively, and overcome deployment challenges.
Interested in learning more? Reach out to the Account Team!
@arung @Paolo Colecchia @Stephen Rhoades @Taonga_Banda @renbafa @morgan Gladwell
Microsoft Tech Community – Latest Blogs –Read More
Copilot now available in classic Outlook for Windows 10 and 11?
Hi.
I’ve noticed that the Copilot feature is now available in my classic Outlook app. However, I’m not sure how to get access to this feature. I’ve checked the settings and options, but I couldn’t find any information on how to enable or configure Copilot.
I’d love to hear any suggestions or solutions on how to access this feature and make the most of it. Thank you.
Hi.I’ve noticed that the Copilot feature is now available in my classic Outlook app. However, I’m not sure how to get access to this feature. I’ve checked the settings and options, but I couldn’t find any information on how to enable or configure Copilot.I’d love to hear any suggestions or solutions on how to access this feature and make the most of it. Thank you. Read More
Blocking Download Access to Teams Channel Meeting Recordings
Our review of the Videos chapter for the Office 365 for IT Pros eBook found a Teams meeting policy setting we hadn’t documented to block downloads for channel meeting recordings. Naturally, this was a disaster, so we spent some time investigating what the policy setting does and if it’s useful in practice. It works, but do you want to block downloads of channel meeting recordings?
https://office365itpros.com/2024/06/13/channel-meeting-recordings/
Our review of the Videos chapter for the Office 365 for IT Pros eBook found a Teams meeting policy setting we hadn’t documented to block downloads for channel meeting recordings. Naturally, this was a disaster, so we spent some time investigating what the policy setting does and if it’s useful in practice. It works, but do you want to block downloads of channel meeting recordings?
https://office365itpros.com/2024/06/13/channel-meeting-recordings/ Read More
The setting of MaxNegPhaseCorrection(Windows Server 2022)
Hello, sorry to bother you at work!
I modified the value of “MaxNegPhaseCorrection” from “HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesW32TimeConfig” and then added the computer to the domain. Then I found that the value of MaxNegPhaseCorrection changed to 0xFFFFFFFF。
I saw on your official website that the default value for domain members is 0xFFFFFFFF。
So I would like to ask the following questions:
1, Why did the above situation occur?
2, Will the settings for W32Time all be reset to default values after joining a computer to a certain domain? Or will only the value of MaxNegPhaseCorrection be reset?
3,Is there any way for me to avoid such situations after adding domains?
My problem is like this. I would greatly appreciate it if you could reply to me.
Wishing you a happy life!
Hello, sorry to bother you at work! I modified the value of “MaxNegPhaseCorrection” from “HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesW32TimeConfig” and then added the computer to the domain. Then I found that the value of MaxNegPhaseCorrection changed to 0xFFFFFFFF。 I saw on your official website that the default value for domain members is 0xFFFFFFFF。 So I would like to ask the following questions: 1, Why did the above situation occur? 2, Will the settings for W32Time all be reset to default values after joining a computer to a certain domain? Or will only the value of MaxNegPhaseCorrection be reset? 3,Is there any way for me to avoid such situations after adding domains? My problem is like this. I would greatly appreciate it if you could reply to me. Wishing you a happy life! Read More
Windows 11 Explorer close, What’s wrong?
Sometimes, I’m just browsing through my files and folders, and then the Explorer window will suddenly disappear. Other times, it might happen when I’m trying to open a specific folder or file. The weird thing is that the Explorer window doesn’t give me any error message or warning before closing. What’s wrong?
Sometimes, I’m just browsing through my files and folders, and then the Explorer window will suddenly disappear. Other times, it might happen when I’m trying to open a specific folder or file. The weird thing is that the Explorer window doesn’t give me any error message or warning before closing. What’s wrong? Read More
Pull data from sheet2 into sheet1 and match with same values
I have been looking through the previous post but have been unable to adapt a formula for my specific requirement.
I have a full data set (design) in sheet one and a partial data set (survey) in sheet two. I want to grab the 3 rows of information from the partial survey data set and insert them adjacent to the design data set to be able to compare.
thanks
I have been looking through the previous post but have been unable to adapt a formula for my specific requirement.I have a full data set (design) in sheet one and a partial data set (survey) in sheet two. I want to grab the 3 rows of information from the partial survey data set and insert them adjacent to the design data set to be able to compare. thanks Read More
Can anyone suggest me a best audio converter for Windows 11?
Hello, this is my first time asking for help, I am looking for a reliable audio converter for Windows 11. I’ve tried a lot of online tools, but they’re always filled with ads or have poor audio quality. Plus, you never know when these things pose a security risk to you. I’m looking for a simple and reliable program that can handle a variety of formats (mp3, m4a) without degrading the audio quality. If it can do batch conversions, that would be even better.
Any recommendations would be super helpful. Thanks a lot!
Hello, this is my first time asking for help, I am looking for a reliable audio converter for Windows 11. I’ve tried a lot of online tools, but they’re always filled with ads or have poor audio quality. Plus, you never know when these things pose a security risk to you. I’m looking for a simple and reliable program that can handle a variety of formats (mp3, m4a) without degrading the audio quality. If it can do batch conversions, that would be even better. Any recommendations would be super helpful. Thanks a lot! Read More
Useability
I want to replace one style with another. But when I go to do it, the “Find Style” list is out of order, and I have to waste time going through the whole list looking for it.
When I try to choose the new style, the “Replace With Style” is out of order, and I have to waste time again, looking for one of Word’s handy styles.
To make things even more fun, the tiny little windows I just mentioned, like so maaaany others, are not resizeable. Little windows that must display dozens of styles, tiny as postage stamps since I fell victim to Word. Forever and ever, Amen.
Then I have to refresh the source of some OLE links. But the option is not in the menus, which since I am a victim of Word dance and dance, as if the party lasted for ever and ever, Amen.
I suppose an organisation as big as yours has a Customer Life Impossibility Design department, staffed, I’m sure, by hundreds of thinking heads, straight out of some very dark, dank, screaming, echoing place.
I want to replace one style with another. But when I go to do it, the “Find Style” list is out of order, and I have to waste time going through the whole list looking for it. When I try to choose the new style, the “Replace With Style” is out of order, and I have to waste time again, looking for one of Word’s handy styles. To make things even more fun, the tiny little windows I just mentioned, like so maaaany others, are not resizeable. Little windows that must display dozens of styles, tiny as postage stamps since I fell victim to Word. Forever and ever, Amen. Then I have to refresh the source of some OLE links. But the option is not in the menus, which since I am a victim of Word dance and dance, as if the party lasted for ever and ever, Amen. I suppose an organisation as big as yours has a Customer Life Impossibility Design department, staffed, I’m sure, by hundreds of thinking heads, straight out of some very dark, dank, screaming, echoing place. Read More
Azure Advisor Cost Optimization workbook – April release
Overview
The Azure Cost Optimization workbook is a powerful tool that helps you monitor and optimize your Azure costs. It provides you with a comprehensive overview of your Azure environment and offers actionable insights and recommendations based on the Well-Architected Framework Cost Optimization pillar.
This workbook is natively available on Azure Advisor for all customers, and an editable version is also available as part of the FinOps toolkit.
If you haven’t used it already, the workbook template is offered in Advisor gallery and does not require any setup.
Here is how you can get started:
1) Navigate to Workbooks gallery in Azure Advisor.
2) Open Cost Optimization workbook template.
3) Select an area to explore.
Release notes
New Additions
New query to identify idle ExpressRoute circuits: Express Route Gateways without a completed circuit (ISP has not completed the connection) still incurs charges, so it’s better to review if they are used or not.
New query to show the Routing Preference for the public Ip addresses: Azure routing preference enables you to choose how your traffic routes between Azure and the Internet. You can choose to route traffic either via the Microsoft network or via the ISP network (public internet). Selecting the right routing preference for your workload can affect the efficiency and cost of your traffic.
New query to show the public Ip addresses with DDoS enabled: If you need to protect fewer than 15 public IP resources, the IP Protection tier is the more cost-effective option. However, if you have more than 15 public IP resources to protect, then the Network Protection tier becomes more cost-effective.
New pie chart to summarize commitment discount savings
New queries to show Azure Hybrid Benefit for Azure SQL Database elastic pools
Feedback
We hope that you find the Azure Cost Optimization workbook useful and that it helps you optimize your Azure spending. We are constantly working to improve the workbook and add new features and enhancements. We welcome your feedback and suggestions on how we can make it better. Please feel free to submit any suggestions through the FinOps Toolkit GitHub repository.
Microsoft Tech Community – Latest Blogs –Read More
Future Upgrades for Social Interaction in SPSE
Our organization currently uses SharePoint 2019 on-premise and we are interested in exploring whether future upgrades to SharePoint Server Subscription Edition (SPSE) might offer enhanced social interaction capabilities for our users. We have seen that Microsoft Viva Engage offers many valuable features for communication and collaboration, such as communities, conversations, and storylines. Unfortunately, cloud and hybrid solutions are not an option for us due to our specific IT policies.
Therefore, I would like to know if there are any plans to make similar social interaction functionalities available in SPSE. Is anyone aware of any future upgrades or expansions in this area for on-premises environments?
Any information or insight would be greatly appreciated.
Thank you in advance for your help!
Best regards,
Adam
Our organization currently uses SharePoint 2019 on-premise and we are interested in exploring whether future upgrades to SharePoint Server Subscription Edition (SPSE) might offer enhanced social interaction capabilities for our users. We have seen that Microsoft Viva Engage offers many valuable features for communication and collaboration, such as communities, conversations, and storylines. Unfortunately, cloud and hybrid solutions are not an option for us due to our specific IT policies.Therefore, I would like to know if there are any plans to make similar social interaction functionalities available in SPSE. Is anyone aware of any future upgrades or expansions in this area for on-premises environments? Any information or insight would be greatly appreciated.Thank you in advance for your help! Best regards,Adam Read More
Extract the text value
Exacting the range and readability from the instrument type How to extract itplease guide mei filter the data( please refer the other sheet) and try to extract. In this method is correct or notis it possible to extract data by using regex extract function
Exacting the range and readability from the instrument type How to extract itplease guide mei filter the data( please refer the other sheet) and try to extract. In this method is correct or notis it possible to extract data by using regex extract function Read More
data matching multiple criteria to be combined
Hello, trying to figure out how to use formulas in Excel to process the following data (top rows in table) and get to the desired result (lower rows in table). Any help is much appreciated. Thank you.
Data to be filtered and combined FruitApplesBananasBananasBananasBananasPears Pears BananasApplesApplesSale?SaleSaleRegularRegularSaleRegularRegularSaleSaleRegularNumber?100100706512040509011080 Desired Result ApplesBananasBananas Pears Apples SaleSaleRegular Regular RegularTotals210310135 90 80
Hello, trying to figure out how to use formulas in Excel to process the following data (top rows in table) and get to the desired result (lower rows in table). Any help is much appreciated. Thank you. Data to be filtered and combined FruitApplesBananasBananasBananasBananasPears Pears BananasApplesApplesSale?SaleSaleRegularRegularSaleRegularRegularSaleSaleRegularNumber?100100706512040509011080 Desired Result ApplesBananasBananas Pears Apples SaleSaleRegular Regular RegularTotals210310135 90 80 Read More
Not able to send email from Outlook 365 (both old and new outlook) using Full MAPI in C++
We have an application which has option to send emails through Outlook with the option of using either Limited MAPI or Full MAPI. Till now it worked smoothly for all the cases.
But we started facing problem after introduction of Outlook 365. Sending emails using Limited MAPI works well, but emails are not getting sent (nor they appear in outbox) using Full MAPI. For some of the developers, emails sending from the classic outlook 365 using Full MAPI works but for few of them it does not work. And sending mails from the new outlook using Full MAPI does not work at all.
We are using C++ to develop the application.
I am hereby attaching the code to send email using Full MAPI. Any help is highly appreciated.
header file –
#pragma once
#define MDB_ONLINE ((ULONG) 0x00000100)
#include <MAPI.h>
#include <vector>
namespace ISolCommExtMAPI64Bridge {
enum EmailPriority
{
ePriorityLow = 0,
ePriorityNormal = 1,
ePriorityHigh = 2,
};
class MAPIMail64
{
public:
MAPIMail64(void);
~MAPIMail64(void);
int Send();
std::vector<CAtlStringW> attachmentList;
std::vector<CAtlStringW> toRecipientstList;
std::vector<CAtlStringW> CCRecipientstList;
std::vector<CAtlStringW> BCCRecipientstList;
CAtlStringW messageText;
EmailPriority priority;
CAtlStringW senderAddress;
CAtlStringW senderName;
CAtlStringW subject;
CAtlStringW type;
CAtlStringW lastErrorString;
bool MAPIAvailable;
CAtlStringW version;
private:
void Cleanup();
HRESULT InitialiseAndLogon();
HRESULT OpenDefaultMessageStore();
HRESULT OpenOutbox();
HRESULT SetProperty(ULONG ulProperty, CAtlStringW itemText);
HRESULT SetPropertyType2(ULONG ulProperty, CAtlStringW itemText);
HRESULT AddHeaderInformationtoMessage();
HRESULT SetPriority();
int SendMailUsingFullMapiAPI();
HRESULT ProcessAttachments();
HRESULT AddAttachment(CAtlStringW filePathName);
CAtlStringW GetRecipients(const std::vector<CAtlStringW> &recipientsList);
CAtlStringW ErrorMessage(DWORD dwError);
LPMAPISESSION mapiSession;
IMAPITable *messageStoresTable;
LPSRowSet defaultStoreProperties;
IMsgStore *defaultStore;
IMAPIFolder *outbox;
IMessage *message;
LPATTACH attachment;
LPSPropValue recipientValues;
LPADRLIST recipientList;
IStream *messageBody;
LPSTREAM pStrmDest;
LPADRBOOK addrBook;
LPENTRYID EID;
};
}
cpp file-
/**************************************************************************************************
Copyright (c) IRIS Software Ltd 2010
All rights reserved.
Module : MAPIMail64.cpp – This code is a 64 bit copy from the MAPIMail class in the IsolCommExtMAPI
sibling to this project.
NOTE THIS IS BUILT AS A 64-BIT APPLICATION.
+———————+ _________________ +—————————–+
| ISolCommExtMAPI.dll | _________________ > | ISolCommExtMAPI64Bridge.exe |
+———————+ NAMED PIPE / +—————————–+
SendMailUsing64BitBridgeProcess() main()
Author : JDLC
Date : 18/02/2019
Desc : Uses MAPI to send emails and attachments via a 64 Bit proxy process.
This gets around the MS Windows restriction of a 32-bit process (IRIS applications)
not being able to invoke 64-bit mail applications such as Outlook.
**************************************************************************************************/
#include <boost/asio.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <windows.h>
#include “stdafx.h”
#include “MAPIMail64.h”
#include <MAPI.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <atlbase.h>
#include <atlcom.h>
#define CbNewFlagList(_c_)
(offsetof(FlagList, ulFlag) + ((_c_) * sizeof(ULONG)))
namespace ISolCommExtMAPI64Bridge {
MAPIMail64::MAPIMail64(void)
{
mapiSession = NULL;
messageStoresTable = NULL;
defaultStoreProperties = NULL;
defaultStore = NULL;
outbox = NULL;
message = NULL;
recipientValues = NULL;
recipientList = NULL;
messageBody = NULL;
attachment = NULL;
pStrmDest = NULL;
addrBook = NULL;
EID = NULL;
messageText = _T(“”);
priority = EmailPriority::ePriorityNormal;
senderAddress = _T(“”);
senderName = _T(“”);
subject = _T(“”);
type = _T(“”);
lastErrorString = _T(“”);
MAPIAvailable = false;
version = _T(“”);
}
MAPIMail64::~MAPIMail64(void)
{
}
//CAtlStringW MAPIMail64::ErrorMessage(HRESULT hr) {
// wchar_t* szError = nullptr;
// FormatMessageW(
// FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
// NULL,
// hr,
// MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
// (LPWSTR)&szError,
// 0,
// NULL);
// CAtlStringW errorMessage(szError);
// LocalFree(szError);
// return errorMessage;
//}
void DisplayError(const CAtlStringW& errorMessage)
{
// Convert CAtlStringW to LPCSTR using WideCharToMultiByte
int length = WideCharToMultiByte(CP_UTF8, 0, errorMessage, -1, NULL, 0, NULL, NULL);
if (length > 0)
{
char* utf8String = new char[length];
WideCharToMultiByte(CP_UTF8, 0, errorMessage, -1, utf8String, length, NULL, NULL);
// Display the error message in a message box
MessageBoxA(NULL, utf8String, “Error”, MB_OK | MB_ICONERROR);
delete[] utf8String;
}
}
/**************************************************************************************************
Send()
Main method for class.
RETURNS – 0 if succesful
1 or 2 if a failure occurs during the send process
**************************************************************************************************/
int MAPIMail64::Send()
{
return SendMailUsingFullMapiAPI();
}
/**************************************************************************************************
SendMailUsingFullMapiAPI() – This is the pre-existing method but in 64-bit build exe
Main method for class. calls in sequence meethods that set up MAPI structures and then attempts to
generate the email. Makes sure everything is cleaned up where necassary.
RETURNS – 0 if succesful
1 or 2 if a failure occurs during the send process
**************************************************************************************************/
int MAPIMail64::SendMailUsingFullMapiAPI()
{
try
{
HRESULT hRes = InitialiseAndLogon();
lastErrorString = “InitialiseAndLogon – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = OpenDefaultMessageStore();
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = OpenOutbox();
lastErrorString = “OpenOutbox – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Release as we no longer need
if(defaultStore != NULL)
{
defaultStore->Release();
defaultStore = NULL;
}
mapiSession->OpenAddressBook(
NULL,
NULL,
NULL,
&addrBook);
//Create the mail message
hRes = outbox->CreateMessage(NULL, 0, &message);
lastErrorString = “outbox->CreateMessage – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “outbox->CreateMessage failed” +ErrorMessage(hRes);
return 1;}
//Dont use address book here – > emails may not be in exchange server
//”To” Recipients and header info
hRes = AddHeaderInformationtoMessage();
lastErrorString = “outbox->AddHeaderInformationtoMessage – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Set Sender Details
hRes = SetPropertyType2(PR_SENDER_NAME,senderName);
lastErrorString = “PR_SENDER_NAME – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = SetPropertyType2(PR_SENDER_EMAIL_ADDRESS, senderAddress);
lastErrorString = “PR_SENDER_EMAIL_ADDRESS – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Message Subject
hRes = SetPropertyType2(PR_SUBJECT, subject);
lastErrorString = “PR_SUBJECT – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Set Low/Normal/High Importance
hRes = SetPriority();
lastErrorString = “SetPriority() – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Message Body
hRes = SetProperty(PR_BODY, messageText);
lastErrorString = “PR_BODY – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = ProcessAttachments();
lastErrorString = “ProcessAttachments – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
// SEND MESSAGE
hRes = message->SubmitMessage(0);
lastErrorString = “message->SubmitMessage – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes))
{
lastErrorString = “message->SubmitMessage failed” +ErrorMessage(hRes);
return 1;
}
}
catch(std::exception& ex)
{
CAtlStringW error(ex.what());
lastErrorString = “MAPIMail64::SendMailUsingMapiStubLibary exception caught : ” + error;
Cleanup();
return 1;
}
catch(…)
{
lastErrorString = “MAPIMail64::SendMailUsingMapiStubLibary unknown exception caught”;
Cleanup();
return 2; //unknown exception
}
Cleanup();
return 0;
}
HRESULT MAPIMail64::InitialiseAndLogon()
{
//Initialise connection
MAPIINIT_0 mapi_ver = {0, MAPI_MULTITHREAD_NOTIFICATIONS};
HRESULT hRes = MAPIInitialize(&mapi_ver);
lastErrorString = “InitialiseAndLogon MAPIInitialize – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPIInitialize failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
//Obtain Default Profile and Logon – if default logon cant be found picker dialog will show.
LPTSTR lpProfile = NULL;
hRes = MAPILogonEx(0, NULL, NULL, MAPI_USE_DEFAULT | MAPI_EXTENDED | MAPI_NEW_SESSION | MAPI_LOGON_UI, &mapiSession);
lastErrorString = “InitialiseAndLogon MAPILogonEx – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPILogonEx failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
return S_OK;
}
HRESULT MAPIMail64::OpenDefaultMessageStore()
{
//Get the Message Store Table
HRESULT hRes = mapiSession->GetMsgStoresTable(0, &messageStoresTable);
lastErrorString = “GetMsgStoresTable – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::InitialiseAndLogon, mapiSession->GetMsgStoresTable failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
// Obtain the default store properties
SizedSPropTagArray(2, resourceFlagsTag);
resourceFlagsTag.cValues = 2; // Number of properties below we are specifying
resourceFlagsTag.aulPropTag[0] = PR_DEFAULT_STORE;
resourceFlagsTag.aulPropTag[1] = PR_ENTRYID;
SRestriction defaultStoreRestrictions;
defaultStoreRestrictions.rt = RES_BITMASK;
defaultStoreRestrictions.res.resBitMask.relBMR = BMR_NEZ;
defaultStoreRestrictions.res.resBitMask.ulPropTag = PR_RESOURCE_FLAGS;
defaultStoreRestrictions.res.resBitMask.ulMask = STATUS_DEFAULT_STORE;
hRes = HrQueryAllRows(messageStoresTable, (LPSPropTagArray)&resourceFlagsTag, &defaultStoreRestrictions, NULL, NULL, &defaultStoreProperties);
lastErrorString = “HrQueryAllRows – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “HrQueryAllRows failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
if (defaultStoreProperties->cRows != 1) // There can only be 1 default store
{
lastErrorString = “MAPIMail64::InitialiseAndLogon, HrQueryAllRows more then 1 default row returned” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return E_FAIL;
}
//Obtain Default Message Stores ID
LPSPropValue defaultStoreId = PpropFindProp(defaultStoreProperties->aRow[0].lpProps, defaultStoreProperties->aRow[0].cValues, PR_ENTRYID);
if (defaultStoreId == NULL){
lastErrorString = “MAPIMail64::InitialiseAndLogon, PpropFindProp failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
//Open Default Message Store
ENTRYID *default_store_entry_id = (LPENTRYID)defaultStoreId->Value.bin.lpb;
//MAPI_NO_CACHE is not being used http://support.microsoft.com/default.aspx?id=834496 as MDB_ONLINE is being used (will this be a issue if other applications have already opened in cache mode)
//Removed MDB_ONLINE as it does not save emails in outbox
hRes = mapiSession->OpenMsgStore(NULL, defaultStoreId->Value.bin.cb, default_store_entry_id, NULL, MAPI_BEST_ACCESS | MDB_WRITE, &defaultStore);
lastErrorString = “OpenMsgStore – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::InitialiseAndLogon, mapiSession->OpenMsgStore failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
//Release as we no longer need
if( defaultStoreProperties != NULL)
{
FreeProws(defaultStoreProperties);
defaultStoreProperties = NULL;
}
if( messageStoresTable != NULL)
{
messageStoresTable->Release();
messageStoresTable = NULL;
}
return S_OK;
}
HRESULT MAPIMail64::OpenOutbox()
{
// Get the properties of the PR_IPM_OUTBOX_ENTRYID property
SizedSPropTagArray(2, outbox_entry_id_query);
outbox_entry_id_query.cValues = 1;
outbox_entry_id_query.aulPropTag[0] = PR_IPM_OUTBOX_ENTRYID;
ULONG resultCount = 0;
SPropValue *results;
HRESULT hRes = defaultStore->GetProps((LPSPropTagArray)&outbox_entry_id_query, 0, &resultCount, &results);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::OpenOutbox, GetProps failed” +ErrorMessage(hRes);
return hRes;
}
if(resultCount != 1) // There can only be 1 outbox
{
lastErrorString = “MAPIMail64::OpenOutbox, Result Count for Outbox’s is more then one – E_FAIL”;
return E_FAIL;
}
//Open the outbox folder //MAPI_BEST_ACCESS | MAPI_MODIFY = returns highest level access allowed
ULONG outboxType;
hRes = defaultStore->OpenEntry(results[0].Value.bin.cb, (LPENTRYID)results[0].Value.bin.lpb, NULL, MAPI_MODIFY , &outboxType, (LPUNKNOWN *)&outbox);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::OpenOutbox, OpenEntry failed” +ErrorMessage(hRes);
return hRes;}
return S_OK;
}
CAtlStringW MAPIMail64::GetRecipients(const std::vector<CAtlStringW> &recipientsList)
{
//Create a list of semi colon delaminated recipients
CAtlStringW recipients = “”;
std::vector<CAtlStringW>::const_iterator itr;
size_t items_remaining = recipientsList.size();
for ( itr = recipientsList.begin(); itr != recipientsList.end(); ++itr )
{
recipients += *itr;
if(items_remaining > 1)
{
recipients += “;”; // We dont want this on the last recipent
}
items_remaining–;
}
return recipients;
}
HRESULT MAPIMail64::ProcessAttachments()
{
HRESULT hRes = S_OK;
std::vector<CAtlStringW>::iterator itr;
for ( itr = attachmentList.begin(); itr != attachmentList.end(); ++itr )
{
hRes = AddAttachment(*itr);
}
return S_OK;
}
HRESULT MAPIMail64::AddAttachment(CAtlStringW filePathName)
{
HRESULT hRes = S_OK;
try
{
pStrmDest = NULL;
ULONG ulAttNum = 0;
std::ifstream is;
is.open (filePathName, std::ifstream::in | std::ios::binary);
if(!is){
return E_FAIL;}
// get length of file:
long length = 0;
is.seekg (0, std::ios::end);
length = static_cast<long> (is.tellg());
is.seekg (0, std::ios::beg);
// allocate memory:
char *buffer = NULL;
buffer = new char[length];
// read data as a block:
is.read(buffer,length);
is.close();
SPropValue *oneProp = NULL;
enum {METHOD,ATTACH_FILENAME,ATTACH_LONG_FILENAME,ATTACH_PATHNAME,ATTACHMENT_FLAGS,ATTACH_SIZE,NUM_ATT_PROPS};
SPropValue props[NUM_ATT_PROPS];
SPropProblemArray* probs=NULL;
ULONG bytesWritten = 0;
// extract file name from attachment file path name
std::wstring attachmentFileName{};
int lastSlashPos = filePathName.ReverseFind(‘\’);
if (lastSlashPos != -1)
{
attachmentFileName = filePathName.Mid(lastSlashPos + 1);
}
else
{
attachmentFileName = filePathName;
}
auto pAttachmentFileName = const_cast<LPWSTR>(attachmentFileName.c_str());
// Create an attachment on the message
hRes = message->CreateAttach(NULL, (ULONG)0, &ulAttNum, &attachment);
if(FAILED(hRes)){
lastErrorString = “message->CreateAttach failed” +ErrorMessage(hRes);
return hRes;}
props[METHOD].ulPropTag =PR_ATTACH_METHOD;
props[METHOD].Value.l =ATTACH_BY_VALUE;
//set attachment properties
props[ATTACH_PATHNAME].ulPropTag =PR_ATTACH_PATHNAME;
props[ATTACH_PATHNAME].Value.lpszW = filePathName.LockBuffer();;
props[ATTACH_FILENAME].ulPropTag =PR_ATTACH_FILENAME;
props[ATTACH_FILENAME].Value.lpszW = pAttachmentFileName;
props[ATTACH_LONG_FILENAME].ulPropTag =PR_ATTACH_LONG_FILENAME;
props[ATTACH_LONG_FILENAME].Value.lpszW = pAttachmentFileName;
props[ATTACHMENT_FLAGS].ulPropTag = PR_MESSAGE_FLAGS;
props[ATTACHMENT_FLAGS].Value.l = 0;
props[ATTACH_SIZE].ulPropTag = PR_ATTACH_SIZE;
props[ATTACH_SIZE].Value.l = length;
hRes=attachment->SetProps(NUM_ATT_PROPS, props, &probs);
if(FAILED(hRes)){
lastErrorString = “attachment->SetProps” +ErrorMessage(hRes);
return hRes;}
hRes = attachment->OpenProperty(PR_ATTACH_DATA_BIN,(LPIID)&IID_IStream, STGM_WRITE, MAPI_CREATE|MAPI_MODIFY , (LPUNKNOWN*)&pStrmDest);
if(FAILED(hRes)){
lastErrorString = “attachment->OpenProperty” +ErrorMessage(hRes);
return hRes;}
hRes = pStrmDest->Write(buffer,length,&bytesWritten);
hRes = pStrmDest->Commit(0);
// Save the changes to the Attachment and message
hRes = attachment->SaveChanges(0);
hRes = message->SaveChanges(KEEP_OPEN_READWRITE);
//Clear up stuff we don’t need
filePathName.UnlockBuffer();
memset(&buffer[0], 0, sizeof(buffer));
delete [] buffer;
delete oneProp;
if( pStrmDest != NULL)
{
pStrmDest->Release();
}
if( attachment != NULL)
{
attachment->Release();
}
}
catch(std::ios_base::failure ex)
{
CAtlStringW error(ex.what());
lastErrorString = “attachment->SetProps ” + error;
return E_FAIL;
}
return hRes;
}
HRESULT MAPIMail64::SetProperty(ULONG ulProperty, CAtlStringW itemText)
{
//Currently used for body text
HRESULT hRes = message->OpenProperty(ulProperty, &IID_IStream, NULL, MAPI_CREATE | MAPI_MODIFY | KEEP_OPEN_READWRITE | FORCE_SAVE | MAPI_ACCESS_MODIFY, (LPUNKNOWN *)&messageBody);
if (FAILED(hRes)){
lastErrorString = “message->OpenProperty” +ErrorMessage(hRes);
return hRes;}
ULONG written;
ULONG body_str_len = itemText.GetLength() * sizeof(wchar_t);
hRes = messageBody->Write(itemText.GetBuffer(), body_str_len, &written);
itemText.ReleaseBuffer();
if (FAILED(hRes)){
lastErrorString = “messageBody->Write” +ErrorMessage(hRes);
return hRes;}
//Make sure expected data was written
if((written != body_str_len) && (written !=NULL))
{
return E_FAIL;
}
BOOL body_updated = FALSE;
hRes = RTFSync(message, RTF_SYNC_RTF_CHANGED | RTF_SYNC_BODY_CHANGED, &body_updated);
if (FAILED(hRes)){
lastErrorString = “RTFSync” +ErrorMessage(hRes);
return hRes;}
if (body_updated)
{
message->SaveChanges(KEEP_OPEN_READWRITE);
}
//Cleanup
messageBody->Commit(STGC_DEFAULT);
messageBody->Release();
messageBody = NULL;
return S_OK;
}
HRESULT MAPIMail64::SetPropertyType2(ULONG ulProperty, CAtlStringW itemText)
{
SPropValue prop;
prop.ulPropTag=ulProperty;
prop.Value.lpszW = itemText.GetBuffer();
itemText.ReleaseBuffer();
HRESULT hRes = message->SetProps(1, &prop, NULL);
if (FAILED(hRes)){
lastErrorString = “SetPropertyType2, “+itemText+ ” , message->SetProps” +ErrorMessage(hRes);
return hRes;}
return hRes;
}
HRESULT MAPIMail64::SetPriority()
{
LONG importance = IMPORTANCE_NORMAL;
switch(priority)
{
case EmailPriority::ePriorityNormal:
importance = IMPORTANCE_NORMAL;
break;
case EmailPriority::ePriorityLow:
importance = IMPORTANCE_LOW;
break;
case EmailPriority::ePriorityHigh:
importance = IMPORTANCE_HIGH;
break;
default:
importance = IMPORTANCE_NORMAL;
}
SPropValue prop;
prop.ulPropTag=PR_IMPORTANCE;
prop.Value.l=importance;
HRESULT hRes = message->SetProps(1, &prop, NULL);
if (FAILED(hRes))
{
lastErrorString = “SetPriority, message->SetProps” +ErrorMessage(hRes);
return hRes;
}
return hRes;
}
HRESULT MAPIMail64::AddHeaderInformationtoMessage()
{
const long bufferMultiplier = 5; // This value equals the size of the recipient values we are submitting
//Allocate email header space
HRESULT hRes = MAPIAllocateBuffer(sizeof(SPropValue) * bufferMultiplier, (LPVOID *)&recipientValues);
lastErrorString = “MAPIAllocateBuffer – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes))
{
lastErrorString = “AddHeaderInformationtoMessage, MAPIAllocateBuffers” +ErrorMessage(hRes);
return hRes;
}
//Create Email header information
recipientValues[0].ulPropTag = PR_ADDRTYPE; //Only used by windows CE, but does not work without it.
recipientValues[0].Value.lpszW = _T(“SMTP”);
recipientValues[1].ulPropTag = PR_RECIPIENT_TYPE;
recipientValues[1].Value.l = MAPI_TO;
CAtlStringW recipients = GetRecipients(toRecipientstList);
CAtlStringW displayName = recipients;
recipientValues[2].ulPropTag = PR_DISPLAY_NAME;
recipientValues[2].Value.lpszW = displayName.GetBuffer();
recipientValues[3].ulPropTag = PR_EMAIL_ADDRESS;
recipientValues[3].Value.lpszW = recipients.GetBuffer();
recipientValues[4].ulPropTag = PR_ENTRYID;
hRes = addrBook->CreateOneOff(
recipientValues[2].Value.lpszW,
recipientValues[0].Value.lpszW,
recipientValues[3].Value.lpszW,
MAPI_UNICODE,
&recipientValues[4].Value.bin.cb,
&EID);
recipientValues[4].Value.bin.lpb = (LPBYTE)EID;
lastErrorString = “CreateOneOff – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
//Create recipient list
hRes = MAPIAllocateBuffer(CbNewADRLIST(1), (LPVOID *)&recipientList);
lastErrorString = “MAPIAllocateBuffer – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes))
{
lastErrorString = “AddHeaderInformationtoMessage, MAPIAllocateBuffer” +ErrorMessage(hRes);
return hRes;
}
//Populate List
recipientList->cEntries = 1;
recipientList->aEntries[0].ulReserved1 = 0;
recipientList->aEntries[0].cValues = 5; //count of value groups we are sending
recipientList->aEntries[0].rgPropVals = recipientValues;
//Add recipient information to the message
hRes = message->ModifyRecipients(MODRECIP_ADD, recipientList);
lastErrorString = “ModifyRecipients – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “AddHeaderInformationtoMessage, message->ModifyRecipients” +ErrorMessage(hRes);
return hRes;}
return S_OK;
}
void MAPIMail64::Cleanup()
{
if(defaultStoreProperties != NULL)
{
FreeProws(defaultStoreProperties);
}
if(defaultStore != NULL)
{
defaultStore->Release();
}
if(messageStoresTable != NULL)
{
messageStoresTable->Release();
}
if(messageBody != NULL)
{
messageBody->Release();
}
if(EID != NULL)
{
MAPIFreeBuffer(EID);
}
if(recipientList != NULL)
{
FreePadrlist(recipientList);
}
if(addrBook != NULL)
{
addrBook->Release();
}
if(message != NULL)
{
message->Release();
}
if(outbox != NULL)
{
outbox->Release();
}
if(mapiSession != NULL)
{
mapiSession->Logoff(NULL, 0, 0);
mapiSession->Release();
}
MAPIUninitialize();
}
CAtlStringW MAPIMail64::ErrorMessage(DWORD dwError)
{
CAtlStringW sErr;
sErr.FormatMessage(_T(” : HRESULT = %1!x!”), dwError);
return sErr;
}
}
We have an application which has option to send emails through Outlook with the option of using either Limited MAPI or Full MAPI. Till now it worked smoothly for all the cases.But we started facing problem after introduction of Outlook 365. Sending emails using Limited MAPI works well, but emails are not getting sent (nor they appear in outbox) using Full MAPI. For some of the developers, emails sending from the classic outlook 365 using Full MAPI works but for few of them it does not work. And sending mails from the new outlook using Full MAPI does not work at all.We are using C++ to develop the application.I am hereby attaching the code to send email using Full MAPI. Any help is highly appreciated.header file – #pragma once
#define MDB_ONLINE ((ULONG) 0x00000100)
#include <MAPI.h>
#include <vector>
namespace ISolCommExtMAPI64Bridge {
enum EmailPriority
{
ePriorityLow = 0,
ePriorityNormal = 1,
ePriorityHigh = 2,
};
class MAPIMail64
{
public:
MAPIMail64(void);
~MAPIMail64(void);
int Send();
std::vector<CAtlStringW> attachmentList;
std::vector<CAtlStringW> toRecipientstList;
std::vector<CAtlStringW> CCRecipientstList;
std::vector<CAtlStringW> BCCRecipientstList;
CAtlStringW messageText;
EmailPriority priority;
CAtlStringW senderAddress;
CAtlStringW senderName;
CAtlStringW subject;
CAtlStringW type;
CAtlStringW lastErrorString;
bool MAPIAvailable;
CAtlStringW version;
private:
void Cleanup();
HRESULT InitialiseAndLogon();
HRESULT OpenDefaultMessageStore();
HRESULT OpenOutbox();
HRESULT SetProperty(ULONG ulProperty, CAtlStringW itemText);
HRESULT SetPropertyType2(ULONG ulProperty, CAtlStringW itemText);
HRESULT AddHeaderInformationtoMessage();
HRESULT SetPriority();
int SendMailUsingFullMapiAPI();
HRESULT ProcessAttachments();
HRESULT AddAttachment(CAtlStringW filePathName);
CAtlStringW GetRecipients(const std::vector<CAtlStringW> &recipientsList);
CAtlStringW ErrorMessage(DWORD dwError);
LPMAPISESSION mapiSession;
IMAPITable *messageStoresTable;
LPSRowSet defaultStoreProperties;
IMsgStore *defaultStore;
IMAPIFolder *outbox;
IMessage *message;
LPATTACH attachment;
LPSPropValue recipientValues;
LPADRLIST recipientList;
IStream *messageBody;
LPSTREAM pStrmDest;
LPADRBOOK addrBook;
LPENTRYID EID;
};
} cpp file- /**************************************************************************************************
Copyright (c) IRIS Software Ltd 2010
All rights reserved.
Module : MAPIMail64.cpp – This code is a 64 bit copy from the MAPIMail class in the IsolCommExtMAPI
sibling to this project.
NOTE THIS IS BUILT AS A 64-BIT APPLICATION.
+———————+ _________________ +—————————–+
| ISolCommExtMAPI.dll | _________________ > | ISolCommExtMAPI64Bridge.exe |
+———————+ NAMED PIPE / +—————————–+
SendMailUsing64BitBridgeProcess() main()
Author : JDLC
Date : 18/02/2019
Desc : Uses MAPI to send emails and attachments via a 64 Bit proxy process.
This gets around the MS Windows restriction of a 32-bit process (IRIS applications)
not being able to invoke 64-bit mail applications such as Outlook.
**************************************************************************************************/
#include <boost/asio.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <windows.h>
#include “stdafx.h”
#include “MAPIMail64.h”
#include <MAPI.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <atlbase.h>
#include <atlcom.h>
#define CbNewFlagList(_c_)
(offsetof(FlagList, ulFlag) + ((_c_) * sizeof(ULONG)))
namespace ISolCommExtMAPI64Bridge {
MAPIMail64::MAPIMail64(void)
{
mapiSession = NULL;
messageStoresTable = NULL;
defaultStoreProperties = NULL;
defaultStore = NULL;
outbox = NULL;
message = NULL;
recipientValues = NULL;
recipientList = NULL;
messageBody = NULL;
attachment = NULL;
pStrmDest = NULL;
addrBook = NULL;
EID = NULL;
messageText = _T(“”);
priority = EmailPriority::ePriorityNormal;
senderAddress = _T(“”);
senderName = _T(“”);
subject = _T(“”);
type = _T(“”);
lastErrorString = _T(“”);
MAPIAvailable = false;
version = _T(“”);
}
MAPIMail64::~MAPIMail64(void)
{
}
//CAtlStringW MAPIMail64::ErrorMessage(HRESULT hr) {
// wchar_t* szError = nullptr;
// FormatMessageW(
// FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
// NULL,
// hr,
// MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
// (LPWSTR)&szError,
// 0,
// NULL);
// CAtlStringW errorMessage(szError);
// LocalFree(szError);
// return errorMessage;
//}
void DisplayError(const CAtlStringW& errorMessage)
{
// Convert CAtlStringW to LPCSTR using WideCharToMultiByte
int length = WideCharToMultiByte(CP_UTF8, 0, errorMessage, -1, NULL, 0, NULL, NULL);
if (length > 0)
{
char* utf8String = new char[length];
WideCharToMultiByte(CP_UTF8, 0, errorMessage, -1, utf8String, length, NULL, NULL);
// Display the error message in a message box
MessageBoxA(NULL, utf8String, “Error”, MB_OK | MB_ICONERROR);
delete[] utf8String;
}
}
/**************************************************************************************************
Send()
Main method for class.
RETURNS – 0 if succesful
1 or 2 if a failure occurs during the send process
**************************************************************************************************/
int MAPIMail64::Send()
{
return SendMailUsingFullMapiAPI();
}
/**************************************************************************************************
SendMailUsingFullMapiAPI() – This is the pre-existing method but in 64-bit build exe
Main method for class. calls in sequence meethods that set up MAPI structures and then attempts to
generate the email. Makes sure everything is cleaned up where necassary.
RETURNS – 0 if succesful
1 or 2 if a failure occurs during the send process
**************************************************************************************************/
int MAPIMail64::SendMailUsingFullMapiAPI()
{
try
{
HRESULT hRes = InitialiseAndLogon();
lastErrorString = “InitialiseAndLogon – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = OpenDefaultMessageStore();
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = OpenOutbox();
lastErrorString = “OpenOutbox – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Release as we no longer need
if(defaultStore != NULL)
{
defaultStore->Release();
defaultStore = NULL;
}
mapiSession->OpenAddressBook(
NULL,
NULL,
NULL,
&addrBook);
//Create the mail message
hRes = outbox->CreateMessage(NULL, 0, &message);
lastErrorString = “outbox->CreateMessage – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “outbox->CreateMessage failed” +ErrorMessage(hRes);
return 1;}
//Dont use address book here – > emails may not be in exchange server
//”To” Recipients and header info
hRes = AddHeaderInformationtoMessage();
lastErrorString = “outbox->AddHeaderInformationtoMessage – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Set Sender Details
hRes = SetPropertyType2(PR_SENDER_NAME,senderName);
lastErrorString = “PR_SENDER_NAME – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = SetPropertyType2(PR_SENDER_EMAIL_ADDRESS, senderAddress);
lastErrorString = “PR_SENDER_EMAIL_ADDRESS – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Message Subject
hRes = SetPropertyType2(PR_SUBJECT, subject);
lastErrorString = “PR_SUBJECT – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Set Low/Normal/High Importance
hRes = SetPriority();
lastErrorString = “SetPriority() – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Message Body
hRes = SetProperty(PR_BODY, messageText);
lastErrorString = “PR_BODY – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = ProcessAttachments();
lastErrorString = “ProcessAttachments – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
// SEND MESSAGE
hRes = message->SubmitMessage(0);
lastErrorString = “message->SubmitMessage – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes))
{
lastErrorString = “message->SubmitMessage failed” +ErrorMessage(hRes);
return 1;
}
}
catch(std::exception& ex)
{
CAtlStringW error(ex.what());
lastErrorString = “MAPIMail64::SendMailUsingMapiStubLibary exception caught : ” + error;
Cleanup();
return 1;
}
catch(…)
{
lastErrorString = “MAPIMail64::SendMailUsingMapiStubLibary unknown exception caught”;
Cleanup();
return 2; //unknown exception
}
Cleanup();
return 0;
}
HRESULT MAPIMail64::InitialiseAndLogon()
{
//Initialise connection
MAPIINIT_0 mapi_ver = {0, MAPI_MULTITHREAD_NOTIFICATIONS};
HRESULT hRes = MAPIInitialize(&mapi_ver);
lastErrorString = “InitialiseAndLogon MAPIInitialize – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPIInitialize failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
//Obtain Default Profile and Logon – if default logon cant be found picker dialog will show.
LPTSTR lpProfile = NULL;
hRes = MAPILogonEx(0, NULL, NULL, MAPI_USE_DEFAULT | MAPI_EXTENDED | MAPI_NEW_SESSION | MAPI_LOGON_UI, &mapiSession);
lastErrorString = “InitialiseAndLogon MAPILogonEx – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPILogonEx failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
return S_OK;
}
HRESULT MAPIMail64::OpenDefaultMessageStore()
{
//Get the Message Store Table
HRESULT hRes = mapiSession->GetMsgStoresTable(0, &messageStoresTable);
lastErrorString = “GetMsgStoresTable – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::InitialiseAndLogon, mapiSession->GetMsgStoresTable failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
// Obtain the default store properties
SizedSPropTagArray(2, resourceFlagsTag);
resourceFlagsTag.cValues = 2; // Number of properties below we are specifying
resourceFlagsTag.aulPropTag[0] = PR_DEFAULT_STORE;
resourceFlagsTag.aulPropTag[1] = PR_ENTRYID;
SRestriction defaultStoreRestrictions;
defaultStoreRestrictions.rt = RES_BITMASK;
defaultStoreRestrictions.res.resBitMask.relBMR = BMR_NEZ;
defaultStoreRestrictions.res.resBitMask.ulPropTag = PR_RESOURCE_FLAGS;
defaultStoreRestrictions.res.resBitMask.ulMask = STATUS_DEFAULT_STORE;
hRes = HrQueryAllRows(messageStoresTable, (LPSPropTagArray)&resourceFlagsTag, &defaultStoreRestrictions, NULL, NULL, &defaultStoreProperties);
lastErrorString = “HrQueryAllRows – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “HrQueryAllRows failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
if (defaultStoreProperties->cRows != 1) // There can only be 1 default store
{
lastErrorString = “MAPIMail64::InitialiseAndLogon, HrQueryAllRows more then 1 default row returned” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return E_FAIL;
}
//Obtain Default Message Stores ID
LPSPropValue defaultStoreId = PpropFindProp(defaultStoreProperties->aRow[0].lpProps, defaultStoreProperties->aRow[0].cValues, PR_ENTRYID);
if (defaultStoreId == NULL){
lastErrorString = “MAPIMail64::InitialiseAndLogon, PpropFindProp failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
//Open Default Message Store
ENTRYID *default_store_entry_id = (LPENTRYID)defaultStoreId->Value.bin.lpb;
//MAPI_NO_CACHE is not being used http://support.microsoft.com/default.aspx?id=834496 as MDB_ONLINE is being used (will this be a issue if other applications have already opened in cache mode)
//Removed MDB_ONLINE as it does not save emails in outbox
hRes = mapiSession->OpenMsgStore(NULL, defaultStoreId->Value.bin.cb, default_store_entry_id, NULL, MAPI_BEST_ACCESS | MDB_WRITE, &defaultStore);
lastErrorString = “OpenMsgStore – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::InitialiseAndLogon, mapiSession->OpenMsgStore failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
//Release as we no longer need
if( defaultStoreProperties != NULL)
{
FreeProws(defaultStoreProperties);
defaultStoreProperties = NULL;
}
if( messageStoresTable != NULL)
{
messageStoresTable->Release();
messageStoresTable = NULL;
}
return S_OK;
}
HRESULT MAPIMail64::OpenOutbox()
{
// Get the properties of the PR_IPM_OUTBOX_ENTRYID property
SizedSPropTagArray(2, outbox_entry_id_query);
outbox_entry_id_query.cValues = 1;
outbox_entry_id_query.aulPropTag[0] = PR_IPM_OUTBOX_ENTRYID;
ULONG resultCount = 0;
SPropValue *results;
HRESULT hRes = defaultStore->GetProps((LPSPropTagArray)&outbox_entry_id_query, 0, &resultCount, &results);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::OpenOutbox, GetProps failed” +ErrorMessage(hRes);
return hRes;
}
if(resultCount != 1) // There can only be 1 outbox
{
lastErrorString = “MAPIMail64::OpenOutbox, Result Count for Outbox’s is more then one – E_FAIL”;
return E_FAIL;
}
//Open the outbox folder //MAPI_BEST_ACCESS | MAPI_MODIFY = returns highest level access allowed
ULONG outboxType;
hRes = defaultStore->OpenEntry(results[0].Value.bin.cb, (LPENTRYID)results[0].Value.bin.lpb, NULL, MAPI_MODIFY , &outboxType, (LPUNKNOWN *)&outbox);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::OpenOutbox, OpenEntry failed” +ErrorMessage(hRes);
return hRes;}
return S_OK;
}
CAtlStringW MAPIMail64::GetRecipients(const std::vector<CAtlStringW> &recipientsList)
{
//Create a list of semi colon delaminated recipients
CAtlStringW recipients = “”;
std::vector<CAtlStringW>::const_iterator itr;
size_t items_remaining = recipientsList.size();
for ( itr = recipientsList.begin(); itr != recipientsList.end(); ++itr )
{
recipients += *itr;
if(items_remaining > 1)
{
recipients += “;”; // We dont want this on the last recipent
}
items_remaining–;
}
return recipients;
}
HRESULT MAPIMail64::ProcessAttachments()
{
HRESULT hRes = S_OK;
std::vector<CAtlStringW>::iterator itr;
for ( itr = attachmentList.begin(); itr != attachmentList.end(); ++itr )
{
hRes = AddAttachment(*itr);
}
return S_OK;
}
HRESULT MAPIMail64::AddAttachment(CAtlStringW filePathName)
{
HRESULT hRes = S_OK;
try
{
pStrmDest = NULL;
ULONG ulAttNum = 0;
std::ifstream is;
is.open (filePathName, std::ifstream::in | std::ios::binary);
if(!is){
return E_FAIL;}
// get length of file:
long length = 0;
is.seekg (0, std::ios::end);
length = static_cast<long> (is.tellg());
is.seekg (0, std::ios::beg);
// allocate memory:
char *buffer = NULL;
buffer = new char[length];
// read data as a block:
is.read(buffer,length);
is.close();
SPropValue *oneProp = NULL;
enum {METHOD,ATTACH_FILENAME,ATTACH_LONG_FILENAME,ATTACH_PATHNAME,ATTACHMENT_FLAGS,ATTACH_SIZE,NUM_ATT_PROPS};
SPropValue props[NUM_ATT_PROPS];
SPropProblemArray* probs=NULL;
ULONG bytesWritten = 0;
// extract file name from attachment file path name
std::wstring attachmentFileName{};
int lastSlashPos = filePathName.ReverseFind(‘\’);
if (lastSlashPos != -1)
{
attachmentFileName = filePathName.Mid(lastSlashPos + 1);
}
else
{
attachmentFileName = filePathName;
}
auto pAttachmentFileName = const_cast<LPWSTR>(attachmentFileName.c_str());
// Create an attachment on the message
hRes = message->CreateAttach(NULL, (ULONG)0, &ulAttNum, &attachment);
if(FAILED(hRes)){
lastErrorString = “message->CreateAttach failed” +ErrorMessage(hRes);
return hRes;}
props[METHOD].ulPropTag =PR_ATTACH_METHOD;
props[METHOD].Value.l =ATTACH_BY_VALUE;
//set attachment properties
props[ATTACH_PATHNAME].ulPropTag =PR_ATTACH_PATHNAME;
props[ATTACH_PATHNAME].Value.lpszW = filePathName.LockBuffer();;
props[ATTACH_FILENAME].ulPropTag =PR_ATTACH_FILENAME;
props[ATTACH_FILENAME].Value.lpszW = pAttachmentFileName;
props[ATTACH_LONG_FILENAME].ulPropTag =PR_ATTACH_LONG_FILENAME;
props[ATTACH_LONG_FILENAME].Value.lpszW = pAttachmentFileName;
props[ATTACHMENT_FLAGS].ulPropTag = PR_MESSAGE_FLAGS;
props[ATTACHMENT_FLAGS].Value.l = 0;
props[ATTACH_SIZE].ulPropTag = PR_ATTACH_SIZE;
props[ATTACH_SIZE].Value.l = length;
hRes=attachment->SetProps(NUM_ATT_PROPS, props, &probs);
if(FAILED(hRes)){
lastErrorString = “attachment->SetProps” +ErrorMessage(hRes);
return hRes;}
hRes = attachment->OpenProperty(PR_ATTACH_DATA_BIN,(LPIID)&IID_IStream, STGM_WRITE, MAPI_CREATE|MAPI_MODIFY , (LPUNKNOWN*)&pStrmDest);
if(FAILED(hRes)){
lastErrorString = “attachment->OpenProperty” +ErrorMessage(hRes);
return hRes;}
hRes = pStrmDest->Write(buffer,length,&bytesWritten);
hRes = pStrmDest->Commit(0);
// Save the changes to the Attachment and message
hRes = attachment->SaveChanges(0);
hRes = message->SaveChanges(KEEP_OPEN_READWRITE);
//Clear up stuff we don’t need
filePathName.UnlockBuffer();
memset(&buffer[0], 0, sizeof(buffer));
delete [] buffer;
delete oneProp;
if( pStrmDest != NULL)
{
pStrmDest->Release();
}
if( attachment != NULL)
{
attachment->Release();
}
}
catch(std::ios_base::failure ex)
{
CAtlStringW error(ex.what());
lastErrorString = “attachment->SetProps ” + error;
return E_FAIL;
}
return hRes;
}
HRESULT MAPIMail64::SetProperty(ULONG ulProperty, CAtlStringW itemText)
{
//Currently used for body text
HRESULT hRes = message->OpenProperty(ulProperty, &IID_IStream, NULL, MAPI_CREATE | MAPI_MODIFY | KEEP_OPEN_READWRITE | FORCE_SAVE | MAPI_ACCESS_MODIFY, (LPUNKNOWN *)&messageBody);
if (FAILED(hRes)){
lastErrorString = “message->OpenProperty” +ErrorMessage(hRes);
return hRes;}
ULONG written;
ULONG body_str_len = itemText.GetLength() * sizeof(wchar_t);
hRes = messageBody->Write(itemText.GetBuffer(), body_str_len, &written);
itemText.ReleaseBuffer();
if (FAILED(hRes)){
lastErrorString = “messageBody->Write” +ErrorMessage(hRes);
return hRes;}
//Make sure expected data was written
if((written != body_str_len) && (written !=NULL))
{
return E_FAIL;
}
BOOL body_updated = FALSE;
hRes = RTFSync(message, RTF_SYNC_RTF_CHANGED | RTF_SYNC_BODY_CHANGED, &body_updated);
if (FAILED(hRes)){
lastErrorString = “RTFSync” +ErrorMessage(hRes);
return hRes;}
if (body_updated)
{
message->SaveChanges(KEEP_OPEN_READWRITE);
}
//Cleanup
messageBody->Commit(STGC_DEFAULT);
messageBody->Release();
messageBody = NULL;
return S_OK;
}
HRESULT MAPIMail64::SetPropertyType2(ULONG ulProperty, CAtlStringW itemText)
{
SPropValue prop;
prop.ulPropTag=ulProperty;
prop.Value.lpszW = itemText.GetBuffer();
itemText.ReleaseBuffer();
HRESULT hRes = message->SetProps(1, &prop, NULL);
if (FAILED(hRes)){
lastErrorString = “SetPropertyType2, “+itemText+ ” , message->SetProps” +ErrorMessage(hRes);
return hRes;}
return hRes;
}
HRESULT MAPIMail64::SetPriority()
{
LONG importance = IMPORTANCE_NORMAL;
switch(priority)
{
case EmailPriority::ePriorityNormal:
importance = IMPORTANCE_NORMAL;
break;
case EmailPriority::ePriorityLow:
importance = IMPORTANCE_LOW;
break;
case EmailPriority::ePriorityHigh:
importance = IMPORTANCE_HIGH;
break;
default:
importance = IMPORTANCE_NORMAL;
}
SPropValue prop;
prop.ulPropTag=PR_IMPORTANCE;
prop.Value.l=importance;
HRESULT hRes = message->SetProps(1, &prop, NULL);
if (FAILED(hRes))
{
lastErrorString = “SetPriority, message->SetProps” +ErrorMessage(hRes);
return hRes;
}
return hRes;
}
HRESULT MAPIMail64::AddHeaderInformationtoMessage()
{
const long bufferMultiplier = 5; // This value equals the size of the recipient values we are submitting
//Allocate email header space
HRESULT hRes = MAPIAllocateBuffer(sizeof(SPropValue) * bufferMultiplier, (LPVOID *)&recipientValues);
lastErrorString = “MAPIAllocateBuffer – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes))
{
lastErrorString = “AddHeaderInformationtoMessage, MAPIAllocateBuffers” +ErrorMessage(hRes);
return hRes;
}
//Create Email header information
recipientValues[0].ulPropTag = PR_ADDRTYPE; //Only used by windows CE, but does not work without it.
recipientValues[0].Value.lpszW = _T(“SMTP”);
recipientValues[1].ulPropTag = PR_RECIPIENT_TYPE;
recipientValues[1].Value.l = MAPI_TO;
CAtlStringW recipients = GetRecipients(toRecipientstList);
CAtlStringW displayName = recipients;
recipientValues[2].ulPropTag = PR_DISPLAY_NAME;
recipientValues[2].Value.lpszW = displayName.GetBuffer();
recipientValues[3].ulPropTag = PR_EMAIL_ADDRESS;
recipientValues[3].Value.lpszW = recipients.GetBuffer();
recipientValues[4].ulPropTag = PR_ENTRYID;
hRes = addrBook->CreateOneOff(
recipientValues[2].Value.lpszW,
recipientValues[0].Value.lpszW,
recipientValues[3].Value.lpszW,
MAPI_UNICODE,
&recipientValues[4].Value.bin.cb,
&EID);
recipientValues[4].Value.bin.lpb = (LPBYTE)EID;
lastErrorString = “CreateOneOff – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
//Create recipient list
hRes = MAPIAllocateBuffer(CbNewADRLIST(1), (LPVOID *)&recipientList);
lastErrorString = “MAPIAllocateBuffer – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes))
{
lastErrorString = “AddHeaderInformationtoMessage, MAPIAllocateBuffer” +ErrorMessage(hRes);
return hRes;
}
//Populate List
recipientList->cEntries = 1;
recipientList->aEntries[0].ulReserved1 = 0;
recipientList->aEntries[0].cValues = 5; //count of value groups we are sending
recipientList->aEntries[0].rgPropVals = recipientValues;
//Add recipient information to the message
hRes = message->ModifyRecipients(MODRECIP_ADD, recipientList);
lastErrorString = “ModifyRecipients – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “AddHeaderInformationtoMessage, message->ModifyRecipients” +ErrorMessage(hRes);
return hRes;}
return S_OK;
}
void MAPIMail64::Cleanup()
{
if(defaultStoreProperties != NULL)
{
FreeProws(defaultStoreProperties);
}
if(defaultStore != NULL)
{
defaultStore->Release();
}
if(messageStoresTable != NULL)
{
messageStoresTable->Release();
}
if(messageBody != NULL)
{
messageBody->Release();
}
if(EID != NULL)
{
MAPIFreeBuffer(EID);
}
if(recipientList != NULL)
{
FreePadrlist(recipientList);
}
if(addrBook != NULL)
{
addrBook->Release();
}
if(message != NULL)
{
message->Release();
}
if(outbox != NULL)
{
outbox->Release();
}
if(mapiSession != NULL)
{
mapiSession->Logoff(NULL, 0, 0);
mapiSession->Release();
}
MAPIUninitialize();
}
CAtlStringW MAPIMail64::ErrorMessage(DWORD dwError)
{
CAtlStringW sErr;
sErr.FormatMessage(_T(” : HRESULT = %1!x!”), dwError);
return sErr;
}