Postgresql libpqxx create temporary table sometimes not exists - postgresql

I need to use a temporary table in my C++ app. After connect I try to do it like this:
bool DBPG::createRulesHelper()
{
bool retVal=false;
PGresult *res = PQexec(m_Connection, "create temporary table if not exists rules_helper(tree_instance_id numeric(38));");
if (PQresultStatus(res) == PGRES_COMMAND_OK) {
PQclear(res);
res=PQexec(m_Connection, "select count(*) from rules_helper;");
if (PQresultStatus(res) == PGRES_TUPLES_OK) {
LOG_I(3, "rules_helper succesfully created");
m_RulesHelperCreated = true;
}
PQclear(res);
}
else
PQclear(res);
}
Here is how I create connection object:
bool DBPG::Connect(const char *user, const char *password, const char *DBName)
{
if (!(user&&*user&&password&&*password&&DBName&&*DBName)) {
LOG_E("Connect error, user||password||DBName is null or empty");
return false;
}
std::stringstream ss;
ss << "postgresql://" << user << ":" << password <<"#" << DBName;
std::string s=ss.str();
const char *connInfo=s.c_str();
m_Connection = PQconnectdb(connInfo);
ConnStatusType st=PQstatus(m_Connection);
if (st != CONNECTION_OK) {
LOG_E("Connect error, status:%d", st);
PQfinish(m_Connection);
m_bIsConnected=m_bConnectionOk=false;
return false;
}
m_bIsConnected=m_bConnectionOk=true;
return createRulesHelper();
}
and later when I tried to use it in an sql sometimes I've got an error as table rules_helper is not exists.
Do I need to wait a couple of seconds after create a temporary table?
Do temporary tables belong to connection? I don't close the connection until the end of my application.
thx,
Zamek

Related

android cardview only show the last result the right amount of times

i'm new to android and java.
i made a cardview and populated it with a simple loop like so:
private ArrayList<DataObject> getTheData(){
ArrayList res = new ArrayList<DataObject>();
for (int index = 0; index < 5; index++){
DataObject obj = new DataObject("shit","happen");
res.add(index,obj);
}
return res;
}
it worked. now i created a database and want to populate it with this data. so i have this:
public ArrayList<DataObject> getData() {
SQLiteDatabase db = this.getReadableDatabase();
ArrayList res = null;
try {
res = new ArrayList<DataObject>();
String selectQuery = "SELECT * FROM quotes a LEFT JOIN authors b ON b.author_id=a.quote_author";
Cursor cursor = db.rawQuery(selectQuery, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
Log.d("CHECKDB",cursor.getString(cursor.getColumnIndex("first_name")) + " " + cursor.getString(cursor.getColumnIndex("last_name")));
Log.d("CHECKDB2",cursor.getString(cursor.getColumnIndex("quote_text")));
DataObject obj = new DataObject(
cursor.getString(cursor.getColumnIndex("first_name")) + " " + cursor.getString(cursor.getColumnIndex("last_name")),
cursor.getString(cursor.getColumnIndex("quote_text"))
);
res.add(obj);
} while (cursor.moveToNext());
}
}
} catch (SQLiteException se) {
Log.e(getClass().getSimpleName(), "Could not create or Open the database");
} finally {
if (db != null)
db.close();
}
return res;
}
the log show all the results, but when i run the app i get the last result the right amount of times. in this case 4 quotes in my database, so i see 4 but the last one 4 times.
please , since i'm new to it, good explanations will be appreciated.
the issue was that my dataobject attributes were set to static

Review of Connection handling and Data access layer using C#, sql server compact 3.5

I am developing a stand alone application, using sql server compact 3.5 sp2 which runs in process. No Database writes involved. Its purely a reporting application. Read many articles about reusing open db connections in case of sql compact(connection pooling) due to its different behavior from sql server.
Quoting the comments from a quiz opened by Erik Ejlskov Jensen Link, where its discussed an open early close late strategy for sql server compact databases. Based on this, with my limited experience I have implemented a not so complex Connection handling+Data access layer. Basically I am unsure if i am writing it in a recommended way. Please could any one point me in the right direction with rooms for improvement in this connection handling approach i have written?
The DbConnection class
public class FkDbConnection
{
private static SqlCeConnection conn;
private static DataTable table;
private static SqlCeCommand cmd;
~FkDbConnection() { conn = null; }
//This will be called when the main winform loads and connection will be open as long as the main form is open
public static string ConnectToDatabase()
{
try {
conn = new SqlCeConnection(ConfigurationManager.ConnectionStrings["Connstr"].ConnectionString);
if (conn.State == ConnectionState.Closed || conn.State == ConnectionState.Broken)
{
conn.Open();
}
return "Connected";
}
catch(SqlCeException e) { return e.Message; }
}
public static void Disconnect()
{
if (conn.State == ConnectionState.Open || conn.State == ConnectionState.Connecting || conn.State == ConnectionState.Fetching)
{
conn.Close();
conn.Dispose();
//conn = null; //does conn have to be set to null?
}
//else the connection might be already closed due to failure in opening it
else if (conn.State == ConnectionState.Closed) {
conn.Dispose();
//conn = null; //does conn have to be set to null?
}
}
/// <summary>
/// Generic Select DataAccess
/// </summary>
/// <param name="sql"> the sql query which needs to be executed by command object </param>
public static DataTable ExecuteSelectCommand(SqlCeCommand comm)
{
if (conn != null && conn.State == ConnectionState.Open)
{
#region block using datareader
using (table = new DataTable())
{
//using statement needed for reader? Its closed below
using (SqlCeDataReader reader = comm.ExecuteReader())
{
table.Load(reader);
reader.Close(); //is it needed?
}
}
#endregion
# region block using dataadpater
//I read DataReader is faster?
//using (SqlCeDataAdapter sda = new SqlCeDataAdapter(cmd))
//{
// using (table = new DataTable())
// {
// sda.Fill(table);
// }
//}
#endregion
//}
}
return table;
}
/// <summary>
/// Get Data
/// </summary>
/// <param name="selectedMPs"> string csv, generated from a list of selected posts(checkboxes) from the UI, which forms the field names used in SELECT </param>
public static DataTable GetDataPostsCars(string selectedMPs)
{
DataTable dt;
//i know this it not secure sql, but will be a separate question to pass column names to select as parameters
string sql = string.Format(
"SELECT " + selectedMPs + " "+
"FROM GdRateFixedPosts");
using (cmd = new SqlCeCommand(sql,conn))
{
cmd.CommandType = CommandType.Text;
//cmd.Parameters.Add("#fromDateTime",DbType.DateTime);
//cmd.Parameters.Add("#toDateTime",DbType.DateTime);
dt = ExecuteSelectCommand(cmd);
}
return dt;
}
}
The Main UI (Form) in which connection opened, for connection to be open through out. 2 other reporting forms are opened from here. Closing main form closes all, at which point connection is closed and disposed.
private void FrmMain_Load(object sender, EventArgs e)
{
string str = FkDbConnection.ConnectToDatabase();
statStDbConnection.Items[0].Text = str;
}
private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
{
FkDbConnection.Disconnect();
}
Comments, improvements on this connection class much appreciated. See my questions also inline code
Thank you.
Updated classes as per Erik's suggestion. with a correction on ExecuteSelectCommand() and an additional class which will instantiate command objs in "using" and pass data to the UI. I intent to add separate GetDataForFormX() methods since the dynamic sql for each form may differ. Hope this is ok?
Correction to Erik's code:
public static DataTable ExecuteSelectCommand(SqlCeCommand comm)
{
var table = new DataTable();
if (conn != null && conn.State == ConnectionState.Open)
{
comm.Connection = conn;
using (SqlCeDataReader reader = comm.ExecuteReader())
{
table.Load(reader);
}
}
return table;
}
New FkDataAccess class for passing Data to UI
public class FkDataAccess
{
public static DataTable GetDataPostsCars(string selectedMPs)
{
var table = new DataTable();
string sql = string.Format(
"SELECT " + selectedMPs + " " +
"FROM GdRateFixedPosts");
if (FkDbConnection.conn != null && FkDbConnection.conn.State == ConnectionState.Open)
{
using (SqlCeCommand cmd = new SqlCeCommand(sql, FkDbConnection.conn))
{
cmd.CommandType = CommandType.Text;
//cmd.Parameters.Add("#fromDateTime",DbType.DateTime);
table = FkDbConnection.ExecuteSelectCommand(cmd);
}
}
return table;
}
//public static DataTable GetDataXY(string selectedvals)
// and so on
}
Too much code in your data access class, makes it unreadable and hard to maintain
The SqlCeonnection object will be disposed when you close it (and when the app closes)
You cannot dispose the DataTable if you want to use it elsewhere, and it is an completely managed object anyway.
It is a good pattern to limit your classes to a single responsibility
public class FkDbConnection
{
private static SqlCeConnection conn;
~FkDbConnection() { conn = null; }
//This will be called when the main winform loads and connection will be open as long as the main form is open
public static void ConnectToDatabase()
{
// Handle failure to open in the caller
conn = new SqlCeConnection(ConfigurationManager.ConnectionStrings["Connstr"].ConnectionString);
conn.Open();
}
public static void Disconnect()
{
if (conn != null)
{
conn.Close();
}
}
public static DataTable ExecuteSelectCommand(SqlCeCommand comm)
{
var table = new DataTable();
if (conn != null && conn.State == ConnectionState.Open)
{
comm.Connection = conn;
using (SqlCeDataReader reader = comm.ExecuteReader())
{
table.Load(reader);
}
}
return table;
}
private void FrmMain_Load(object sender, EventArgs e)
{
try
{
FkDbConnection.ConnectToDatabase();
statStDbConnection.Items[0].Text = "Connected";
}
catch (Exception ex)
{
//Inform use that we canot proceed, what she can do to remedy, and exit
}
}
private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
{
FkDbConnection.Disconnect();
}

EF - I can not assign values to foreign keys via Create

I'm a fairly green beginner (1 year training altogether) in C#.
My assignment was to create tables in a DB through Visual Studio 2010 - I did via EF. Now I want to write a simple Console program to fill those tables with values. In SQL MS they look right. In the last few lines of my code, I get the error msg that the CreateBestellung()-method only takes two arguments though. That'll be the two columns I created in this table. But how do I assign values to the foreign key fields? Couldn't find anything about this so far.
private static void bestellungAnlegen(playgroundEntities context)
{
Console.Clear();
Console.WriteLine("Neue Bestellung anlegen");
int kdId = -1;
int wrId = -1;
int anzahl = 0;
int id = -1;
// Validierung der Werte
do
{
Console.Write("Kunden ID: ");
if (int.TryParse(Console.ReadLine(), out kdId))
{
kdId = int.Parse(Console.ReadLine());
}
} while (kdId == -1);
do
{
Console.Write("Waren ID: ");
if (int.TryParse(Console.ReadLine(), out kdId))
{
kdId = int.Parse(Console.ReadLine());
}
} while (wrId == -1);
do
{
Console.Write("Anzahl: ");
if (int.TryParse(Console.ReadLine(), out anzahl))
{
if (anzahl >= 0)
{
anzahl = int.Parse(Console.ReadLine());
}
else anzahl = 0;
}
} while (anzahl == 0);
Bestellung neueBestellung =
Bestellung.CreateBestellung(id, anzahl, kdId, wrId);
context.Bestellungen.AddObject(neueBestellung);
}
This can only be a wild (but educated) guess. I think the method call should be
Bestellung neueBestellung = Bestellung.CreateBestellung(id, anzahl);
followed by
neueBestellung.kdId = kdId;
neueBestellung.wrId = wrId;

Boost io_service stopping?

I am working on an NPAPI plugin that allows to use sockets with local inside browsers and I am using Boost sockets for this.
My usage right now is just open the socket write a meesage, read, send a closing message and close and then repeat (I know it is stupid to close and open everytime but I can not change that).
The problem is that after the second open I am unable to read from the socket, until las changes I was able to open write but never got the info back and now it seems the io_service thread is just dying.
I have read a lot of tutorial and info, but no one seems to open several client sockets as I am trying to do.
Here are the class that stores the socket info and handler:
SocketInfo.hpp
class SocketInfo
{
public:
void start_read();
void handle_read(const boost::system::error_code& error, std::size_t bytes_transferred);
FB::JSObjectPtr m_callback;
boost::shared_ptr<boost::asio::ip::tcp::socket> m_socket;
char data_[SOCKETS_API_BUFFER];
int key;
boost::shared_ptr<SocketsAPI> parent;
};
SocketInfo.cpp
void SocketInfo::start_read()
{
parent->log("start_read" + boost::lexical_cast<std::string>(key));
m_socket->async_receive(boost::asio::buffer(data_, SOCKETS_API_BUFFER),
boost::bind(&SocketInfo::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void SocketInfo::handle_read(const boost::system::error_code& error,
std::size_t bytes_transferred)
{
if (!error) {
parent->log("handle_read" + boost::lexical_cast<std::string>(key));
std::string str(&data_[0], &data_[0] + bytes_transferred);
m_callback->InvokeAsync("processData", FB::variant_list_of(str));
start_read();
} else {
parent->log("error closing " + boost::lexical_cast<std::string>(key));
m_callback->InvokeAsync("processCancel", FB::variant_list_of());
parent->do_close(*this);
}
}
SocketApi.h
class SocketsAPI : public FB::JSAPIAuto
{
public:
SocketsAPI(const SocketsPtr& plugin, const FB::BrowserHostPtr& host) :
m_plugin(plugin), m_host(host)
{
... FireBreath code here ...
//Start thread with work
workPtr.reset( new boost::asio::io_service::work(io_service));
ioThreadPtr.reset(new boost::thread(boost::bind(&boost::asio::io_service::run, &io_service)));
}
virtual ~SocketsAPI() {
workPtr.reset();
if (ioThreadPtr) {
ioThreadPtr->join();
}
};
//Socket Methods
int open(const int port, const FB::JSObjectPtr &callback );
void close(const int key);
void write(const int key, const std::string data);
// Method echo
FB::variant echo(const FB::variant& msg);
void do_close(const SocketInfo socket);
void log(const std::string &str);
private:
mapType sockets;
boost::asio::io_service io_service;
boost::shared_ptr<boost::thread> ioThreadPtr;
boost::shared_ptr<boost::asio::io_service::work> workPtr;
void checkOpen(const SocketInfo socket);
void do_write(const std::string data, const SocketInfo socket);
void start_read(const SocketInfo socket);
void empty_handle(const boost::system::error_code& error);
int getFirstEmpty();
SocketInfo getSocket(const int key);
};
SocketAPI.cpp
int SocketsAPI::open(const int port, const FB::JSObjectPtr &callback )
{
log("open");
boost::shared_ptr<SocketInfo> socket;
socket.reset(new SocketInfo);
socket->m_socket.reset(new boost::asio::ip::tcp::socket(io_service));
socket->m_callback = callback;
ip::tcp::endpoint tcp(ip::address::from_string("127.0.0.1"), port);
boost::system::error_code errorcode;
socket->m_socket->connect(tcp, errorcode);
if (errorcode) {
trace("Connection failed: ", errorcode.message());
return -1;
}
log("conenected");
boost::asio::socket_base::keep_alive o(true);
socket->m_socket->set_option(o);
int key = getFirstEmpty();
socket->key = key;
socket->parent.reset(this);
sockets.insert ( std::pair<int,boost::shared_ptr<SocketInfo>>(key,socket));
socket->start_read();
if (io_service.stopped()) {
log("Resetting service");
io_service.reset();
}
return key;
}
void SocketsAPI::close(const int key)
{
SocketInfo socket = getSocket(key);
checkOpen(socket);
log("close");
io_service.post(boost::bind(&SocketsAPI::do_close, this, socket));
}
void SocketsAPI::write(const int key, const std::string data)
{
log("write socket " + boost::lexical_cast<std::string>(key));
SocketInfo socket = getSocket(key);
checkOpen(socket);
io_service.post(boost::bind(&SocketsAPI::do_write, this, Base64::decode(data), socket));
}
void SocketsAPI::checkOpen(const SocketInfo socket)
{
log("checkOpen");
if (!socket.m_socket || !socket.m_socket->is_open()) {
trace("Socket not opened", "");
throw FB::script_error("There is no open socket");
}
}
void SocketsAPI::do_write(const std::string data,
const SocketInfo socket)
{
log("do_write " + boost::lexical_cast<std::string>(socket.key));
if (!socket.m_socket->is_open()) {
return;
}
boost::asio::async_write(*(socket.m_socket.get()),
boost::asio::buffer(&data[0], data.size()),
boost::bind(&SocketsAPI::empty_handle, this, boost::asio::placeholders::error)
);
}
void SocketsAPI::empty_handle(const boost::system::error_code& error)
{
if (error) {
trace("Error writing: ", error.message());
}
}
void SocketsAPI::do_close(const SocketInfo socket)
{
log("do_close");
if (!socket.m_socket || !socket.m_socket->is_open()) {
return;
}
boost::system::error_code errorcode;
socket.m_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, errorcode);
if (errorcode) {
trace("Closing failed: ", errorcode.message());
}
socket.m_socket->close(errorcode);
if (errorcode) {
trace("Closing2 failed: ", errorcode.message());
}
mapType::iterator iter = sockets.find(socket.key);
if (iter != sockets.end()) {
sockets.erase (iter);
}
log("do_close end");
}
int SocketsAPI::getFirstEmpty() {
int i = 0;
mapType::iterator iter;
while(true) {
iter = sockets.find(i);
if (iter == sockets.end()) {
return i;
}
i++;
}
}
SocketInfo SocketsAPI::getSocket(const int key) {
mapType::iterator iter = sockets.find(key);
if (iter == sockets.end()) {
trace("Socket not found", "");
throw FB::script_error("Socket not found");
}
log("socket " + boost::lexical_cast<std::string>(key) +" found");
return *iter->second.get();
}
I am sure that something could be improved (please tell me) but I can not find the error why after the second open it just doesn't work.
Traces of excution:
open
conenected
start_read0
write socket 0
socket 0 found
checkOpen
do_write 0
handle_read0
start_read0
write socket 0
socket 0 found
checkOpen
do_write 0
socket 0 found
checkOpen
close
do_close
do_close end
open
conenected
start_read0
write socket 0
socket 0 found
checkOpen
It seems that io_service.run() just stops but the thread is still working and io_service is not stopped so I am not sure what could be happening.
Ok I found the error it was a lot simpler than I thought it just throw an exception and that stop everything but as I was using it inside a browser I didn't notice that.
Still I am unable to solve the problem so you can check: Boost bind object freed on read handler to share some insight.

How to send a email in VC++?

I am new to VC++ and programming.
I have to write code to send a email in VC++.
How do I go about it? Please help!!
Here's how I do it with the ATL classes. I think you need one of the paid versions of VC++ to get ATL. You will need the name of your email server.
CSMTPConnection smtp;
if (!smtp.Connect(m_strEmailServer))
return false;
// start generating the email message; remember to call CoInitialize somewhere in the app before this
CMimeMessage msg;
msg.SetSubject(m_strSubject);
msg.SetSender(m_strSender);
// repeat the following as necessary
msg.AddRecipient(strSingleRecipient);
msg.AddText(m_strBody);
if (!smtp.SendMessage(msg))
return false;
return true;
Can your software require MAPI? That's an interface that provides a fairly simple interface to whatever the user's installed as default email program is.
If so, then you can use something like the following:
/////////////////////////////////////////////////////////
// CMapiSendMessage
// Allows for simplified message generation and transmission using Simple MAPI
class CMapiSendMessage
{
public:
// constant data
enum RecipientType { FROM = MAPI_ORIG, TO = MAPI_TO, CC = MAPI_CC, BCC = MAPI_BCC };
// ctors
CMapiSendMessage() { }
// accessors
CString GetSubject() const { return m_subject; }
CString & GetMessage() { return m_message; }
const CString & GetMessage() const { return m_message; }
// setters
void AddRecipient(RecipientType type, const CStringA & strName, const CStringA & strAddress = "")
{
m_recipients.push_back(Recipient(type, strName, strAddress));
}
void SetSubject(const CString & strSubject)
{
m_subject = strSubject;
}
void SetMessage(const CString & strMessage)
{
m_message = strMessage;
}
void AddAttachment(const CFilename & filename)
{
m_attachments.push_back(filename.cstring());
}
// actions
ULONG Send(bool bShowDialog, HWND hwndParent); // send this message, show or don't show the user the message dialog
// returns SUCCESS_SUCCESS if all went well
// returns MAPI_USER_ABORT if user aborted the send
// returns MAPI_E_LOGIN_FAILURE if unable to login to MAPI service (user login failed)
ULONG AfxSend(bool bShowDialog, bool bShowError); // send message with special processing for an MFC application
// set bShowError if you wish to automatically show standard MFC error messages if the send message failed
protected:
// types
struct Recipient
{
RecipientType type;
CStringA name;
CStringA address;
Recipient(RecipientType _type, const CStringA & _name, const CStringA & _address = "") :
type(_type), name(_name), address(_address)
{
}
// force default ctor to set type to zero (not random)
Recipient() : type(FROM) { }
};
typedef std::vector<Recipient> RecipientVector;
typedef std::vector<CString> AttachmentVector;
CMailAPI32 m_api; // MAPI interface
RecipientVector m_recipients; // recipients (TO:, CC:, and BCC:)
CString m_subject; // message subject
CString m_message; // message body text
AttachmentVector m_attachments; // file attachments
};
And the CPP half:
typedef std::vector<CMapiRecipDesc> MapiRecipDescVector;
typedef std::vector<CMapiFileDesc> MapiFileDescVector;
//////////////////////////////////////////////////////////////////////
// CMailAPI32
//////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// CMapiSendMessage
ULONG CMapiSendMessage::Send(bool bShowDialog, HWND hwndParent) // send, show user interface - let them edit the message and have final choice in send/cancel
{
// save the cwd
CPathname cwd(CPathname::GetCurrent());
// build the recipients array
const size_t total_recipients = m_recipients.size();
MapiRecipDescVector recipients(total_recipients);
for (size_t i = 0; i < total_recipients; ++i)
{
CMapiRecipDesc recipient;
recipient.ulReserved = 0L;
recipient.ulRecipClass = m_recipients[i].type;
recipient.lpszName = const_cast<LPSTR>(GetPtrOrNull(m_recipients[i].name));
recipient.lpszAddress = const_cast<LPSTR>(GetPtrOrNull(m_recipients[i].address));
recipient.ulEIDSize = 0;
recipient.lpEntryID = NULL;
recipients[i] = recipient;
}
// build attachments array
const size_t total_attachments = m_attachments.size();
MapiFileDescVector attachments(total_attachments);
for (size_t j = 0; j < total_attachments; ++j)
{
CFilename filename(m_attachments[j]);
if (!filename.Exists())
ThrowLabeledException(FString(_T("File does not exist: %s"), filename.c_str()));
// get the fully specified path
size_t size = filename.cstring().GetLength() + 1;
attachments[j].lpszPathName = new char[size];
#ifdef _UNICODE
_wcstombsz(attachments[j].lpszPathName, filename, size);
#else
lstrcpy(attachments[j].lpszPathName, filename);
#endif
// build an appropriate title for the attachment
CString strTitle = filename.GetFullName();
size = strTitle.GetLength() + 1;
attachments[j].lpszFileName = new char[size];
#ifdef _UNICODE
_wcstombsz(attachments[j].lpszFileName, strTitle, size);
#else
lstrcpy(attachments[j].lpszFileName, strTitle);
#endif
// attachment not embedded in the mapi_msg text;
attachments[j].nPosition = (ULONG)-1;
}
// prepare the mapi_msg
MapiMessage mapi_msg =
{
0, // reserved, must be 0
(LPSTR)GetPtrOrNull(m_subject), // subject
(LPSTR)GetPtrOrNull(m_message), // body
NULL, // NULL = interpersonal mapi_msg
NULL, // no date; MAPISendMail ignores it
NULL, // no conversation ID
0L, // no flags, MAPISendMail ignores it
NULL, // no originator, this is ignored too
total_recipients, // no. recipients
total_recipients ? &recipients[0] : NULL, // array of recipients
total_attachments, // no. attachments
total_attachments ? &attachments[0] : NULL // array of attachments
};
// send mail
FLAGS flags = MAPI_LOGON_UI;
BitSetIf(flags, MAPI_DIALOG, bShowDialog);
ULONG nError = m_api.SendMail(
NULL, // temporary session
(ULONG)hwndParent,
&mapi_msg,
flags,
0
);
// delete the attachment filenames
for (int k = total_attachments; k ; --k)
{
delete [] attachments[k-1].lpszPathName;
delete [] attachments[k-1].lpszFileName;
}
// restore CWD
cwd.SetCurrent();
// indicate if we succeeded or not
return nError;
}
ULONG CMapiSendMessage::AfxSend(bool bShowDialog, bool bReportError)
{
// prepare for modal dialog box
AfxGetApp()->EnableModeless(FALSE);
HWND hWndTop;
CWnd * pParentWnd = CWnd::GetSafeOwner(NULL, &hWndTop);
// some extra precautions are required to use MAPISendMail as it
// tends to enable the parent window in between dialogs (after
// the login dialog, but before the send note dialog).
pParentWnd->SetCapture();
::SetFocus(NULL);
pParentWnd->m_nFlags |= WF_STAYDISABLED;
// attempt to send the message
ULONG nError = Send(bShowDialog, pParentWnd->GetSafeHwnd());
// display error to user
if (nError != SUCCESS_SUCCESS &&
nError != MAPI_USER_ABORT &&
nError != MAPI_E_LOGIN_FAILURE)
{
AfxMessageBox(AFX_IDP_FAILED_MAPI_SEND);
}
// after returning from the MAPISendMail call, the window must
// be re-enabled and focus returned to the frame to undo the workaround
// done before the MAPI call.
::ReleaseCapture();
pParentWnd->m_nFlags &= ~WF_STAYDISABLED;
pParentWnd->EnableWindow(TRUE);
::SetActiveWindow(NULL);
pParentWnd->SetActiveWindow();
pParentWnd->SetFocus();
if (hWndTop != NULL)
::EnableWindow(hWndTop, TRUE);
AfxGetApp()->EnableModeless(TRUE);
// report success or not
return nError;
}
This is from my codebase - and I'm not making an effort to unravel it from my own libraries. But you should be able to "fill in the blanks".
Good luck!