Showing posts with label MFC. Show all posts
Showing posts with label MFC. Show all posts

Saturday, 27 July 2013

Property Sheets


If you find yourself working with MFC property sheets and run into a first-chance exception inside the  ::OnInitDialog method, check that all your dialogs resources have the right windows styles.


 
If you are using dialog resources , check that the dialog resources have the following properties:
 
Border: Thin
Disabled: True
Style: Child

In my case, one of the dialog resource had the 'Border' property set to 'Dialog Frame' and 'Sytle' to 'Pop up'

According to MSDN documentation , for the CPropertySheet::DoModal() method, all the windows styles should be disabled  with the exception of :

DS_3DLOOK
Obsolete. The system automatically applies the three-dimensional look to dialog boxes created by applications.
DS_CONTROL
Creates a dialog box that works well as a child window of another dialog box, much like a page in a property sheet. This style allows the user to tab among the control windows of a child dialog box, use its accelerator keys, and so on.
WS_CHILD
0x40000000L
The window is a child window. A window with this style cannot have a menu bar. This style cannot be used with the WS_POPUP style.
WS_TABSTOP
0x00010000L
The window is a control that can receive the keyboard focus when the user presses the TAB key. Pressing the TAB key changes the keyboard focus to the next control with the WS_TABSTOP style.
You can turn this style on and off to change dialog box navigation. To change this style after a window has been created, use the SetWindowLong function. For user-created windows and modeless dialogs to work with tab stops, alter the message loop to call the IsDialogMessage function.

 
And these are optional windows styles, that can be used with the guarantee that they won't cause First-chance exceptions.

DS_SHELLFONT
Indicates that the dialog box should use the system font. The typeface member of the extended dialog box template must be set to MS Shell Dlg. Otherwise, this style has no effect. It is also recommended that you use the DIALOGEX Resource, rather than theDIALOG Resource. For more information, see Dialog Box Fonts.
The system selects a font using the font data specified in the pointsizeweight, and italicmembers. The system passes a handle to the font to the dialog box and to each control by sending them the WM_SETFONT message. For descriptions of the format of this font data, see DLGTEMPLATEEX.
If neither DS_SHELLFONT nor DS_SETFONT is specified, the extended dialog box template does not include the font data.
DS_LOCALEDIT
Applies to 16-bit applications only. This style directs edit controls in the dialog box to allocate memory from the application's data segment. Otherwise, edit controls allocate storage from a global memory object
WS_CLIPCHILDREN
0x02000000L
Excludes the area occupied by child windows when drawing occurs within the parent window. This style is used when creating the parent window.
 

If you dialog resources are Kosha and you still get a First-change exception is very likely you are experience an exception that is expected (by design) when calling CPropertySheet::DoModal() or CPropertySheet::Create()

You can find out more about this expected exception 'that is safely handled by the operating system' following this link.

On that Microsoft page you will find three methods for resolving the issue.
 
Until next time, see ya.
 
 

Sunday, 27 January 2013

rand_s

As we know the rand function in C++ generates a pseudo random number. The rand_s function is a version
of the rand function with security enhancements.

If you ever have wanted to use the security enhanced version ,rand_s,  and after including the
necessary reference to the stdlib library  , #include ,  you still get a compile error error C3861:

error C3861: 'rand_s': identifier not found

You will need to include a macro on your code. My personal choice, which  I found more convenient,
is to add the macro _CRT_RAND_S in the "C++\Preprocessor  property page






You can find more information on rand_s on this following MDSN page

Sunday, 25 November 2012

Building a DSN less connection for OLE DB

Needed to hook a Windows application to an MS-Access database . The windows application would insert records into the tables when the end user choose one of the application's menu option.

I thought that it would be good idea to free up the end user from having to create the databases DSN using the ODBC data source administrator control panel. A DSN less connection string look like this

"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\myapplication\\mycooldb.accdb"

The only down size of this is that I would have to hard code this somewhere on the source code.

Wait! Since the database will be distributed with the application what about if  'Data Source"' property gets built dynamically.

To achieve this it's need to retrieve the directory of the running application , append to this the database name and make sure that the Provider property is included.

CString myDatabasePath;
CString connString (_T("Provider=Microsoft.ACE.OLEDB.12.0;Data Source = "));

//this get the file path of the application ,chop  off the executable name and
// add the database name
GetModuleFileName(NULL,myDatabasePath.GetBufferSetLength(MAX_PATH),MAX_PATH);
myDatabasePath.Truncate(targetDir.ReverseFind('\\') + 1) ;
myDatabasePath +=        "mycooldb.accdb";

// add the database path (i.e C\myapplication\\mycooldb.accdb) to the connection string
connString += myDatabasePath

//need to do this since  OLE DB is used
BSTR bstrConnString = connString.AllocSysString();
hr = _db.OpenFromInitializationString(bstrConnString);

//free up string used
targetDir.ReleaseBuffer(MAX_PATH);
SysFreeString(bstrConnString);

Wednesday, 14 March 2012

MFC data access using OLE DB

Hello Boys and Girls,

Today I want to give an example on how to access and retrieve data from a relational database , in this case Sybase SQL Anywhere, using MFC.

Yes MFC. MFC is an early attempt by Microsfot on creating a Object Oriented API for Windows development. Basically MFC is wrapper API for the underlaying Windows API.
For this example I am using Tools For Men (AKA Visual Studio 2010) and C++.

The high level steps are:

1. Establishing connection to the database. For this I will be using OLE DB
2. Call a store procedure.

Establishing a connection to a database using OLE DB.

For opening a connection to our SQL Anywhere a CDatasource,CSession and initialisation string is needed:

CDataSource _db;
CSession session
LPTSTR connString = _T("Provider=MSDASQL.1;Persist Security Info=False;User ID=admin;Extended Properties=\"DSN=hoteldb;UID=admin;\"");

Since OLE DB is made of  set of interfaces that implement COM a HRESULT variable is needed to keep track of the result of our operation.

HRESULT hr;

hr = _db.OpenFromInitializationString(connString);
if(FAILED(hr)){
AfxMessageBox(_T("It can't connect to database"),0,0);
}

hr = session.Open(_db);
if(FAILED(hr)){
AfxMessageBox(_T("it can't open database session"),0,0);
}

Once that we have succesfull open a session we can use this instance to access our database.

Call a Sybase SQL Anywhere store procedure

In this example my recordset is bound to the data source via my CAccessor class CCount. For an explanation of what a CAccesors are and their role in OLE DB you can go
here


When opening the recordset I am passing a store procedure, togehter with session. Store procedures are an elegant way of executing SQL operations on databases.

CCommand<CAccessor<CCount>> recordset;
hr = recordset.Open(session,storeProcCall );
if(FAILED(hr)){
AfxMessageBox(_T("Can't open table"),0,0);
}
while(recordset.MoveNext() == S_OK){
passes= recordset.m_count;
}

After getting the result of the record set is a good idea to close the session and recordset object.

CloseSession();
recordset.Close();

Then I can pass or return my result to a calling method:

return passes;

The code for the accessor type is very simple:

Class CCount{
public:
int m_count;

//input
TCHAR m_From[50];
TCHAR m_To[50];
TCHAR m_PassCode[50];

//Parameter Accessor
BEGIN_PARAM_MAP(CCount)
SET_PARAM_TYPE(DBPARAMIO_INPUT)
COLUMN_ENTRY(1, m_From)
SET_PARAM_TYPE(DBPARAMIO_INPUT)
COLUMN_ENTRY(2, m_To)
SET_PARAM_TYPE(DBPARAMIO_INPUT)
COLUMN_ENTRY(3, m_PassCode)
END_PARAM_MAP()

BEGIN_COLUMN_MAP(CCount)
COLUMN_ENTRY(1,m_count)
END_COLUMN_MAP()
};

I found CString MFC class very handy when building the store procedure parameters:

CString storeProcCall ("CALL admin.GuestPassDetails(");
storeProcCall.Append(from);
storeProcCall.Append(_T(","));
storeProcCall.Append(to);
storeProcCall.Append(_T(","));
storeProcCall.Append(passesCode);
storeProcCall.Append(_T(") "));

This CString is passed to the recordset as I mentioned previoulsy:

hr = recordset.Open(session,storeProcCall );

See you next time.