Solved

Using HDC.FromHandle and CDC::GetSafeHdc

Posted on 1998-08-31
8
1,575 Views
Last Modified: 2013-11-19
OK, I'm trying to pass a CDC* to my ActiveX control by passing the HDC of the control and using it to display.  

Now to test my problem, I tested a few functions and tried to see if the CDC was really my new CDC or not.

TRACE1( "Map Mode: %d\n",  pDC->GetMapMode( ));

HDC hDC = pDC->GetSafeHdc( );
CDC* pTestDC = CDC::FromHandle( hDC );

TRACE1( "Map Mode: %d\n",  pTestDC->GetMapMode( ));

Hmmm! The mapping modes are now different! When printing, it went from MM_TEXT to MM_ANISOTROPIC.

SOOO... the way that I'm converting it doesn't work.  So how do I do it?

HDC hDC = pDC->GetSafeHdc( );
CDC pTestDC;
pTestDC.Attach( hDC );

Doesn't seem to work either.  Anyone?

Phillip

0
Comment
Question by:psdavis
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 2
  • 2
8 Comments
 
LVL 2

Expert Comment

by:milenvk
ID: 1321511
What about using SaveDC and RestoreDC? Right in your code this will look like:

TRACE1( "Map Mode: %d\n",  pDC->GetMapMode( ));

HDC hDC = pDC->GetSafeHdc( );
int nSavedDC = SaveDC(hDC);
CDC* pTestDC = CDC::FromHandle( hDC );
RestoreDC(pTestDC->m_hDC, nSavedDC);

TRACE1( "Map Mode: %d\n",  pTestDC->GetMapMode( ));

This is not as elegant but at least solves the problem :-) You just have to pass to your control the value returned by SaveDC along with the HDC itself.
0
 
LVL 7

Author Comment

by:psdavis
ID: 1321512
I'm already around the problem, so I'm not looking for a kludge.  I just really want to know how you're supposed to do it in the first place, but thanks.

0
 
LVL 2

Expert Comment

by:milenvk
ID: 1321513
I looked the the Attach version of your test.
I looked at the code of CDC::Attach() and it seems that there shouldn't be a different result. Why don't you debug the functions deeper in the MFC code. Check if both HDCs in the first and second trace are the same (they should be). If they are not try to spot where and how the HDC gets changed (frankly, I don't see how this is possible looking at the MFC code). And finally if they are equal try to find out why the map mode changed during the transition.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 8

Accepted Solution

by:
Answers2000 earned 70 total points
ID: 1321514
I'm a little unclear on what's in the app and what's in the ActiveX. So if I my assumptions are incorrect, it might help if you could make that a bit clearer.

One general point, then a stab at the answer

GENERAL POINT

Aside from anything else though, you need to look at what you're trying to do.  

1. An MFC app and an MFC ActiveX component are using different copies of MFC, that means you can not share MFC objects between them.  So in your case you can't point a CDC *, but will have to pass an HDC and reconstruct in the ActiveX control.  You seem to have realized this (?) as I suspect you pass hDC into the ActiveX control.
HDC hDC = pDC->GetSafeHdc( );
    ^
    |
    |
  You're passing this ?

2. If you really want to share MFC objects between an MFC app and a DLL, you need to make the DLL an MFC extension DLL.  That's an aside though.


THE ANSWER ?

1. Now putting all that aside you need to remember that the CDC object encapsulates two HDCs (m_hDC and m_hAttribDC - see the help topic on the CDC Class Overview).  

2. MFC gets/sets all attributes thru m_hAttribDC and does drawing thru m_hDC.  Normally m_hAttribDC and m_hDC contain the same HDC - but NOT always (for example a metafile).

3. Now looking at your code, both variants do
HDC hDC = pDC->GetSafeHdc( );
Which gets m_hDC from the CDC.  
However any mapping modes etc. are set thru m_hAttribDC which may be a different HDC.  Reconstructing (both methods you do are okay) you loose the m_hAttribDC value and its settings.

The solution then is to
EITHER
(i) pass both HDC's into the ActiveX control (and reconstruct the CDC from both of them) - adding a SetAttribDC on pTestDC should do this for you
OR
(ii) Set the attributes on the m_hDC to match those on m_hAttribDC (if they really are different HDCs) before passing thru in to the ActiveX
OR
(iii) Switch to MFC Extension DLL architecture and just share the CDC objects between the main app and the DLL.

0
 
LVL 7

Author Comment

by:psdavis
ID: 1321515
I'll look into both comments.  Thanks guys.

To clarify, I'm eliminating worrying about the ActiveX passing until I figure out how to do it in just the code snipplet.  Then I'll worry.

HDC hDC = pDC->GetSafeHdc( );

Yes, I was passing the hDC.  To get around it, I'm currently passing the pDC as a long* to my ActiveX control.  Once it gets there, I'm casting it back to a CDC*.  Actually works great.  I'm doing it with the tooltips as well.  No problems.

Phillip

0
 
LVL 7

Author Comment

by:psdavis
ID: 1321516
Answers2000,

So this is the final solution for this code snipplet?

// To get the two HDC

HDC hDC       = pDC->m_hDC;
HDC hAttribDC = pDC->m_hAttribDC;

// To convert it back

CDC* pTestDC = CDC::FromHandle( hDC );
pTestDC->SetAttribDC( hAttribDC );

// or alternatively

CDC pTestDC;
pTestDC.Attach( hDC );
pTestDC.SetAttribDC( hAttribDC );

// Correct?

Phillip

0
 
LVL 8

Expert Comment

by:Answers2000
ID: 1321517
Yes I believe so Phillip,

I've been reading the CDC sources and it looks right to me, though I have to say I haven't actually tried a test project.

Let me know how you get on

Incidentally I believe I've figured out milenvk's work round works.  It's because the SaveDC get's the attribute DC's attributes saved in the main app, and the restore puts the attributes back in the ActiveX's attribute DC (which may not be the same attribute DC as in the main app).

The only funny thing is (as usual) the MFC doc's are less than 100% clear when the attribute DC won't be the same as the hDC.

As far as I can tell your final code should work in all cases though.
0
 
LVL 7

Author Comment

by:psdavis
ID: 1321518
> Incidentally I believe I've figured out milenvk's work round works

I agree completely, but it was more of a intellectual question than a solution question.

Thanks,
Phillip
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Attackers love to prey on accounts that have privileges. Reducing privileged accounts and protecting privileged accounts therefore is paramount. Users, groups, and service accounts need to be protected to help protect the entire Active Directory …

732 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question