Solved

Using HDC.FromHandle and CDC::GetSafeHdc

Posted on 1998-08-31
8
1,508 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
  • 4
  • 2
  • 2
8 Comments
 
LVL 2

Expert Comment

by:milenvk
Comment Utility
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
Comment Utility
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
Comment Utility
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
 
LVL 8

Accepted Solution

by:
Answers2000 earned 70 total points
Comment Utility
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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 7

Author Comment

by:psdavis
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
> 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

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
repeatEnd java challenge 42 83
Process filename extension 3 154
conditional code and condition difference 9 65
wordcount challenge 11 71
Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
Introduction: Database storage, where is the exe actually on the disc? Playing a game selected randomly (how to generate random numbers).  Error trapping with try..catch to help the code run even if something goes wrong. Continuing from the seve…
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.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

763 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now