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

Thursday, June 7, 2007

Non-Polymorphic class And dynamic_cast

dynamic_cast, Non_polymorphic class , Some mfc thoughts
----------------------------------------------------------------------------------------

dynamic_cast couldn't be applied to "non-polymorphic" class . So what is this "non-polymorphic" class ? A class which has no virtual function is caled the non_polymorphic class. If you try to use dynamic_cast with non-polymorphic class. the result will be compile error. For example the code written below cause to an error.

class SuperBase
{
};
class Derived : public SuperBase
{
};


Derived* pDer = new Derived;
SuperBase* pBase = pDer;
Derived* pTest = dynamic_cast<Derived*>(pBase);

This code will try to cast pBase to Derived* , but it will not compile. To correct it use static_cast.

Derived* pTest = static_cast<Derived*>(pBase);

See the code below
CWnd *pWnd = GetDlgItem(IDC_BUTTON1); // IDC_BUTTON1 is a windows button control in a dialog.

Try to cast this pWnd to CButton* with dynamic_cast will give you a null pointer, like dynamic_cast<CButton*>(pWnd) will give you a null pointer. Means the cast is not working . Why ?????

Because mfc is creating some temporary objects inside , to reduce overehad. I will try to explain this later....


Sunday, June 3, 2007

Difference Between Parent And Owner windows

Parent , Owner Windows Vc++
--------------------------------------------

We all know the relation ship between parent and child windows.
So if i ask you this question "What is the difference between Owner window andv owned window' ?? If you know the answer leave now.. No need to read the rest of the page. Otherwise you may find it interesting to read.

I don't want to write more about this topic.. Since this is a simple question..
Child window means , its drawing is limited to the parent region , and also it z order is also changed according to parent.

But if you consider owner windows it can draw outside the parent window region ,
But if you close the main Top-level window , both of these windows will close..

So when creating a child window using CreateWindow function , there is an option for providing parent for the window.

If you are creating a child window with WS_POPUP style that window automatically becomes a owner window, and it can draw outside the region)(means (o,0) position indicates top Left corner of desktop). Otherwise it is a normal child window.
That's it...

Monday, May 28, 2007

MFC Temporary Handles

If we want a CWnd object from  a hwnd , the first functions coming to my mind is these.
CWnd -> Attach()
or
CWnd::FromHandle().


The difference is this , the CWnd::FromHandle first checks if the specified hwnd is already in the Permenent handle map. If so it
returns the CWnd * from the map. If it can't find it searches in the Temporary map and returns. if it couldn't see the hwnd in both
permenent and temporary map it will create a new CWnd * object and add it to temporary map.


So the point is this. The temporary objects are deleted during the idle time. So don't store the pointer returned from CWnd::FromHandle like functions ( CPen, CDC , CGDIObject etc ).


If we are calling Attach. it should be detached, otherwise during the destruction of the class (CWnd), the destructor calls the ::DestroyWindow API , to destroy the attached window( may be we don't want to do that). Also don't give non-MFC window pointer to Attach function. It is not valid . If you want , then use FromHandle function

Monday, May 7, 2007

Easy way to Disable IME window in an Win32 Application

In this world of Unicode still we often do non Unicode applications. But there is a feature in windows operating system it allows to enter Unicode characters or characters other than basic ascii character set to our application.So What happens is when user press enter key these unicode characters will turn to "????" .Because our application is non Unicode .

So there is a easy way to disappear this IME window when our application comes to front. Microsoft provides api like

1 ImmDisableIme
2 ImmAssociateContext

So if you want to make disappear the ime window for a particular window in you application , you can use ImmAssociateContext.

like ImmAssociateContext(YourHwnd,0) , If don't wan to use the ime feature at all use ImmDisableIme().

The ImmDisableIme will cause to disable IME for all windows in you application .One important thing you should call this function , before any window is created.
Like ImmDisableIme( GetCurrentThreadID()). For an mfc application the best place to call is from CYourApp::InitInstance() , where CYourApp derived from CWinApp.



Friday, January 5, 2007

Implementation of the MFC Document View Architecture.

We know that every MFC application has a application class CWinApp which is derived from CWinThread class. Here First I am trying to find how the wizard creates the Frame, document, view classes, and how they are organized?


 For an MFC application the best place to start is the InitInstance() function. This function is called from AfxWinMain. If IniInstance return false it indicates that application has failed to start. So this causes to immediately terminate the application. So in this case the wizard writes the InitInstance function like this

BOOL CTestApp::InitInstance()
{


   INITCOMMONCONTROLSEX InitCtrls;
   InitCommonControlsEx(&InitCtrls);


   CWinApp::InitInstance();


   CSingleDocTemplate* pDocTemplate;
   pDocTemplate = new CSingleDocTemplate(IDR_MAINFRAME,                        RUNTIME_CLASS(CtestviewDoc),RUNTIME_CLASS(CMainFrame),      
                        RUNTIME_CLASS(CtestviewView));


   if (!pDocTemplate)      return FALSE;
   AddDocTemplate(pDocTemplate);


   CCommandLineInfo cmdInfo;
   ParseCommandLine(cmdInfo);


   if (!ProcessShellCommand(cmdInfo))return FALSE;


     m_pMainWnd->ShowWindow(SW_SHOW);
            m_pMainWnd->UpdateWindow();
           return TRUE;
}


First it creates a CSingleDocumentTemplate class’s object. CSingleDocumentTemplate is derived from CDocumentTemplate.


CDocumentTemplate class contains the following members of CRuntime class.
CRuntimeClass* m_pDocClass;         // class for creating new documents
CRuntimeClass* m_pFrameClass;       // class for creating new frames
CRuntimeClass* m_pViewClass;        // class for creating new views
CRuntimeClass* m_pOleFrameClass;    // class for creating in-place
CRuntimeClass* m_pOleViewClass;

In the IniInstance of CWinapp class wizard is creating a CSingleDocumentTemplate class object and initializes it with Run time class objects of our View. Frame, Doc classes.


 After that the app class stores this newly created CSingleDocumentTemplate class object by calling a function AddDocTemplate(CDocTemplate* pTemplate). This is a member function of class CWinApp.

void CWinApp::AddDocTemplate(CDocTemplate* pTemplate)
{
      if (m_pDocManager == NULL)
            m_pDocManager = new CDocManager;
      m_pDocManager->AddDocTemplate(pTemplate);
}


m_pDocManager is a member variable of class CWinApp. Declared as  CDocManager* m_pDocManager; CDocManager contains a pointer array.  CWinApp::AddDocTemplate simply calls the function of m_pDocManager->AddDocTemplate(). Then Next line of IniInstance is like this.


CCommandLineInfo cmdInfo;The default command line is FileNew , that means create a new new document.


ParseCommandLine(cmdInfo); The parse command line looks the argv of main function and parses it ,


If finds anything it adds it to the cmdInfo object. For example if the command line is app sample.txt it sets the m_nShellCommand memmber of CCommandLineInfo class to FileOpen ,  And m_strFileName to the sample.txt. So in this case there is no command line arguments. Since the default command line is FileNew the ParseCommandLine lines just returns. The Next step wizrd does is calling the function CWinApp::ProcessShellCommand(cmdInfo). The ProcessShellCommand is written like this(removed all other codes.). So in our case it FileNew

switch (rCmdInfo.m_nShellCommand)
{


      case CCommandLineInfo::FileNew:
            OnFileNew()
            break;
      case CCommandLineInfo::FileOpen:
            break;
   case CCommandLineInfo::FilePrintTo:
      case CCommandLineInfo::FilePrint:
            break;
      case CCommandLineInfo::FileDDE:
      case CCommandLineInfo::AppRegister:
            break;
      case CCommandLineInfo::AppUnregister:
            break;
};

 In this case it finaly calls CWinApp::OnFileNew() function. Where all creation takes place. The CWinApp::OnFileNew simlpy calls the doc manager object’s OnFileNew. Like this


void CWinApp::OnFileNew()
{
      if (m_pDocManager != NULL)
            m_pDocManager->OnFileNew();
}

The CDocManager ::OnFileNew() checks for multiple templates . In this case here only 1 temmplate is present(becs this is SDI APP ). Earlier I told that CDocManager stores a list of CDocuemntTemplate class object. Here it gets the First object from list and calls the OpenDocumentFile(0) function. (psuedo code shown below )

void CDocManager::OnFileNew()
{
  CDocTemplate* pTemplate = CDocTemplate*)m_templateList.GetHead();
  pTemplate->OpenDocumentFile(NULL);
}

The next part is the important part , where all creation takes place. So i am going to dig the CSingleDocument::OpenDoumentFile() function.This function creates the the object of CDocument ( our applications CDocument derived object) , Application's Frame class(CFrameWnd) and application's View class(CView). Well , lets see how these things happpens. Below i am presenting the skelton of CSingleDocTemplate::OpenDocumentFile() function.


CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible)
{
   CDocument *pDocument = NULL;
   CFrameWnd *pFrameWnd = NULL;
   pDocument = CreateNewDocument(); 
   pFrameWnd = CreateNewFrame();
}

Looking through the above function , we can understand that the Wizrd created document object by calling a function CreateNewObject function. So what is in this CreateNewDocument function ?? . i did dig again and find that , here wizard uses the CRuntime class's object .
Here i am rembering you about CDocTemplate class contains 3 CRuntime class members representing View,Document,Frame. Since CSingleDocTemaplte is derived from CDocTemplate it also gets these members. What i am trying to convey is that the CreateNewDocument function creates a new document using these runtime class. If you remember the Documnet class properly you can see the macros  DECLARE_DYNCREATE and  IMPLEMENT_DYNCREATE .

CDocument * CDocTemplate::CreateNewDocument()
{
  CDocument* pDocument = (CDocument*)m_pDocClass->CreateObject();
   return pDocument;

}

So what these macros doing ? we can see a CreateObject function in CreateNewDocument function. (m_pDocClass->CreateObject()). Actually this function is implemented by the IMPLEMENT_DYNCREATE macro. it just returning a pointer to our class.


Below is the implemenation of IMPLEMENT_DYNCREATE .

IMPLEMENT_DYNCREATE(class_name, base_class_name) \
CObject* PASCAL class_name::CreateObject() \
{
return new class_name; } \


 IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \
class_name::CreateObject, NULL)

The CreateObject function is highlighted in red. So i think that part is clear. We learned how wizard is creating a new application Document class object. the next is with FrameWnd . Lets look the CreateNewFrame function. The CreateNewFrame function also creates the object of CFrameWnd class by using the Runtime class associated with the CDocTemplate class.The CreateNewFrame function is shown below.

CFrameWnd* CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther)
{
 CCreateContext context;
 context.m_pCurrentFrame = pOther;
 context.m_pCurrentDoc = pDoc;
 context.m_pNewViewClass = m_pViewClass;
 context.m_pNewDocTemplate = this;
 if (pDoc != NULL) ASSERT_VALID(pDoc);


 ASSERT(m_nIDResource != 0); // must have a resource ID to load from
 CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject();
 ASSERT_KINDOF(CFrameWnd, pFrame);
 pFrame->LoadFrame(m_nIDResource,WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL,&context);
 return pFrame;
}

The m_pFrameClass is a member of CDocTemplate Initialized in IniInistance function. (if you are not remembering refer top of this article ).m_pFrameClass is a CRuntimeClass's object. So the by calling the m_pFrameClass ->CreateObject() returns a pointer to fhe application CMainFrame (derived from CFrameWnd ) class object. The next step is creating the  window by calling LoadFrame().


The CFrameWnd::LoadFrame creates the window by calling the Create method , and  loads the accelerator information.  So what happend to View ???  . Lets look the code.. If you look at the CDocTemplate::CreateNewFrame() function above shown , you can see that the function creates an pbject of CCreateContext. ( CCreateContext context;). The wizrd assiging the context.pNewViewClass with runtime class of our view (m_pViewClass , this gets value on CSingleDocumentTemplate creation. refer IniInstance on the top. ).