Monday, April 11, 2005

Class 10 - Using MFC

This class is not fully related to AutoCAD and ObjectARX but it covers an overview of MFC library. This library will allow you to create rich interfaces for your ObjectARX applications easily and with professional style.

Introduction

MFC (Microsoft Foundation Classes) is a powerful library made to allow windows programmers to easily create rich interfaces following the windows standard interface.

The MFC class tree is huge and obviously it is not the objective of this class to make you an MFC wizard. I will present here the main concepts involved when using MFC inside AutoCAD and how to take advantage of its power.

If you would like to use MFC inside your ObjectARX application you will need to link it with MFC libraries which can be done dynamically or statically. Currently ObjectARX only support dynamic linked MFC DLL applications because some of AutoCAD libraries were dynamic linked with MFC and you can't mix static and dynamic linked libraries. To make your application dynamic linked with MFC you need to select MFC Extension DLL option when creating your application.

Resource Management

One of the most important concepts when dealing with MFC libraries is that they are based on resources. Resources are rich information such as bitmaps, icons, string tables, dialog layouts, etc. Each DLL has its own resource package that could be used only by itself or shared with other DLLs (Resource only DLLs for example).

The problem is that your ObjectARX application is running into AutoCAD host application which has its own resources. To solve this problem you should switch the resource context to your DLL, use them, and then switch back to AutoCAD. This can be done manually but there is a couple of classes to help you to easily do that.

The first class, called CAcExtensionModule which will handle your module's own resource and the default resources. To make your application take advantage of this class you will need to create an instance of this class inside each module DllMain() function. This can be done using the following:
AC_IMPLEMENT_EXTENSION_MODULE(theArxDLL);

HINSTANCE _hdllInstance = NULL;

extern "C" int APIENTRY

DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) {

// Remove this if you use lpReserved
UNREFERENCED_PARAMETER(lpReserved);

if (dwReason == DLL_PROCESS_ATTACH) {

theArxDLL.AttachInstance(hInstance);

hdllInstance = hInstance;

}

else if (dwReason == DLL_PROCESS_DETACH) {

theArxDLL.DetachInstance();

}

return 1; // ok

}
The second class, called CAcModuleResourceOverride is a handy class that performs the switch from AutoCAD's resource to your application's resource when it is instantiated and then, when it is destroyed, switch back to AutoCAD. To use it, just declare an object of it before using your own resources. When it goes out of scope it will be destroyed and its destructor will switch back. So, this is the way to go:
CAcModuleResourceOverride res;

CMyDialo dlg;

dlg.DoModal();


This way you will successfully create your dialog and won't face strange errors like: "An unsupported operation was attempted". Another possible error happens with other dialog appearing instead of yours! Crazy hum? Remember that this applies to any type of resources including strings placed into string tables.

Using MFC Built-in support
Autodesk has also provided us some great classes to make our application looks like a native AutoCAD feature and work much more integrated with AutoCAD's interface. There are two collections of MFC built-in classes which are grouped by AcUi and AdUi prefixes. The AcUi prefixed classes are made to work inside AutoCAD environment and the AdUi classes are made to work outside AutoCAD but, due to license agreement, could be used only on applications that interact with AutoCAD.

Each of these two classes allow us to create buttons like those one we can see inside AutoCAD native dialogs, allow us to create smart edit controls modified to work with angles, points, texts, etc. There are also great combo boxes that allows us to create Layer like combos, linetype combos, color combos, etc.

These classes really provide you a professional appearance. There are also other advanced features like hack into AutoCAD Options dialog creating your own tab, create dockable dialogs, among many others.

Take a look inside ObjectARX documentation to see a complete list of those classes.

25 comments :

JC GAY said...

Great !!!
I was wondering how to display some dialog boxes inside AutoCAD, and now i got my answer !
Thanks and go on with these classes.

Anonymous said...

Hi

I have more than two DWG file opened in my application.
I need to tile two Dwg only according to DB Pointer or AcApDocument.

Regards,
M.S

Anonymous said...

dear Fernando,
I have a problem.
In my application I have more than two DWG file opened but I need to tile vertically or horizontally two DWG file.

I use

CMDIFrameWnd *m_pWndFrame;
m_pWndFrame = acedGetAcadFrame();
m_pWndFrame->MDITile(MDITILE_VERTICAL);

but this code tile all DWG.

So Only I need to tile two DWG file.
Regards,
MS from Jordan

Fernando Malard said...

Hi M.S,

When you say "tile" are you saying tiled windows, do you need to put the two DWG documents tiled at screen?

Regards,
Fernando.

Fernando Malard said...

Hi, now I got your problem.
I'm afraid you can not do that once the MDI window tiled feature works for all opened and visible documents. Maybe if you hide the undesired document windows you may reach your desired effect.

Regards,
Fernando.

Anonymous said...

Dear Fernando
Iam MS, thanks for your solution about how to tilde two window if have more than two window.

But I don’t now how to getting CDocument from CMDIChildwnd to disable other window.

I have a weak solution but not good solution.

CFrameWnd * pFrame = (CFrameWnd *)(AfxGetApp()->m_pMainWnd); return (CMyDoc *) pFrame->GetActiveDocument();

Then active next doucument.


Please give me other solution for this problem without Active Document, because Active document consume time
(How to Getting Doucment??)

Regards,
MS

Fernando Malard said...

Hi MS,

First, to better understand AutoCAD documents, take a look at this sample:

\ObjectARX 2007\samples\editor\docman

Each AcApDocument object has a method called cDoc():

virtual CDocument *
cDoc() const = 0;
"Returns the associated MFC CDocument object pointer for this AcApDocument."

With CDocument pointer you will gain access to MFC stuff.

Also, take a look at AcApDocManager class which will help you a lot.

I would recomend you to iterate AutoCAD documents using ObjectARX code like docman sample shows.

Regards,
Fernando.

Anonymous said...

Thank you very much

Really I happy, Thanks again.

Good by

Best Regards,
MS

Anonymous said...

Hi Fernando,

Please how to make Document disable from CDocument pointer

Regards,
M.S

Fernando Malard said...

Hi MS,

I haven't tried this but I guess you will have to iterate through all document views and hide one by one with the ShowWindow(SW_HIDE) method.

Regards,
Fernando.

Anonymous said...

Hi Fernando,
This is my function I Store Each DWG DB in AcArray then get document pointer. But when Execute these two statment

pFirstView->ShowWindow(SW_HIDE);
pFirstView->UpdateWindow();

Only the black screen hidden without window so when I tile horizontally the all window has been tile.



for(int i = 0; i < m_pDBArray->length() ;i++)
{
AcDbDatabase * pDataBase = (AcDbDatabase *)m_pDBArray->at(i);
AcApDocManager *docMgr = acDocManager ;
AcApDocument *doc;
doc = docMgr->document(pDataBase);
CDocument *cdoc = doc->cDoc();

POSITION pos = cdoc->GetFirstViewPosition();
CView* pFirstView = cdoc->GetNextView( pos );
pFirstView->ShowWindow(SW_HIDE);
pFirstView->UpdateWindow();
pFirstView->ShowWindow(SW_SHOW);
pFirstView->UpdateWindow();
while (pos != NULL)
{
CView* pView = cdoc->GetNextView(pos);
pView->ShowWindow(SW_HIDE);
pView->UpdateWindow();
}

}
Do you have any idea how to get window to make it hidden

Regards,
MS

Anonymous said...

Hi fernando,
My Last post whithout this two statment.

pFirstView->ShowWindow(SW_SHOW);
pFirstView->UpdateWindow();

regards,
ms

Anonymous said...

Hi Fernando,
Yes it work
I use parent of CView

POSITION pos = cdoc->GetFirstViewPosition();
CView* pFirstView = cdoc->GetNextView( pos );
CWnd * pcwnd= pFirstView->GetParent();
pcwnd->ShowWindow(SW_HIDE);
.
.
.
CMDIFrameWnd *m_pWndFrame;
m_pWndFrame = acedGetAcadFrame();
m_pWndFrame->MDITile(MDITILE_VERTICAL);
.
.
.
CDocument *cdoc = doc->cDoc();
POSITION pos = cdoc->GetFirstViewPosition();
.
.
.
CView* pFirstView = cdoc->GetNextView( pos );
CWnd * pcwnd= pFirstView->GetParent();
pcwnd->CenterWindow();
pcwnd->ShowWindow(SW_MINIMIZE);
pcwnd->CenterWindow();

Thanks a lot

Regards,
M.S

Fernando Malard said...

Hi MS,

I'm happy to know this has solved your issue.

Regards.

Bordei said...

Hello!
I have a static library. I would like to link this library with ObjectArx libraries..
It is possible? I try to indicate the headers and lib files from ObjectArx , and to
#include "arxHeaders.h" in my StdAfx.h static library header.. I have got a lot of ACRX_DECLARE_MEMBERS erorrs..

I'm not allowed to link a static libary with ObjectArx?

Kind regards!
Ioan

Fernando Malard said...

Hello Ioan,

You can use external DLL libraries with or without MFC inside your ObjectARX application. You need to export the methods/classes you want by using AFX_EXT_CLASS macro or your own __declspec(dllexport)/(dllimport). Take a look at VC++ documentation about the use of these classes.

Inside your ObjectARX modules you will need to import these functions/classes by including their .H files and linking with their .LIB files.

In other hand your libraries can also be ARX or DBX modules. In fact your application can be composed by several ARX, DBX and DLL modules. All of them can be exported/imported using the same approach.

If you plan to build a non-ObjectARX library it cannot include any of ObjectARX headers and cannot link with any library.

Regards,
Fernando.

xmax said...

Hi

i have a problem when hatching,
display message is An unsupported
operation was attempted........

Fernando Malard said...

Hi xmax,

This error is related to a wrong resource map or the missing CAcModuleResourceOverride object.

Check your BEGIN_MESSAGE_MAP section (put a breakpoint and follow its flow to see if there is some wrong resource map). Further, check the DoDataExchange.

Regards.

Dawie said...

Hi,

I am trying to use MFC dialogs in my arx app, but they are simply not displaying. I followed your instructions and altered by DllMain(), I am also using the CAcModuleResourceOverride class. I even resorted in passing in the AppHandle, still no luck. Any ideas?

Dawid

Fernando Malard said...

Hello Dawid,

Is your ARX mixed-mode (.NET)?
Are you using which version of ObjectARX? 2007?

Anonymous said...

Hello Fernando,

First, congratulations for your blog! I teach myself on ObjectARX programming, and you are my reference!

Now, my problem : I try to display in AutoCAD 2009 a MFC DialogBoxe defined in a MFC DLL module through my personnal AutoCAD command defined in my ARXProject.

But when I call DoModal() in my MFC DLL module, I have an Assert in objcore.cpp :

BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
ENSURE(this != NULL);
// it better be in valid memory, at least for CObject size
ASSERT(AfxIsValidAddress(this, sizeof(CObject)));
...
...
}

That is what I have done :


In my ARX module :
------------------

void CSendingCommandsApp::AdskSendingCommands_TEST1(void)
{
CAcModuleResourceOverride temp;

CDisplay a;
a.Display( acedGetAcadResourceInstance(), acedGetAcadFrame() );
}

In my MFC DLL :
--------------

In the CDisplay.h file :

static HINSTANCE hInstanceSafe;

In the entry point of my MFC DLL module :

DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
CDisplay::hInstanceSafe = hInstance;
...
...

}


In the CDisplay.cpp file :

HINSTANCE CDisplay::hInstanceSafe = NULL;

void CDisplay::Display( HINSTANCE h, CWnd* pParent )
{
AfxSetResourceHandle( hInstanceSafe );

CDlgBidon* pDlg = new CDlgBidon( pParent );
pDlg->DoModal();
pDlg->DestroyWindow();
delete pDlg;

AfxSetResourceHandle( h );
}

What's wrong?? I've tried everything I could find in the Internet, but nothing work for me (or maybe I've not understood...).
Could you help me?

I precise that I use Autocad Architecture 2009 with ObjectARX2009 and Visual Studio 2005 SP1. I've used the objectARX Wizard to create my ARX project skeleton.

Thanks for your help,

Best regards,

Sophie.

Fernando Malard said...

Hi Sophie,

Did you mark your project as Mixed-mode during ARXWizard?

Could you build a minimum sample which reproduce this behavior and send to me by e-mail (fpmalard@yahoo.com.br)?

Regards,

Estudiante said...

Fernando, I was wondering how to use MFC Dialogs but this is exactly what I needed, thanks!

SNEHA said...

Hi...
How to change Font properties of EditBox?
Thanking you!

Fernando Malard said...

You will need to take a look at its documentation.

Cheers.