|
Must I ship the same .h file that I've just used to compile a .DLL with classes with this .DLL?
I mean: I don't want to let others view/know what private/protected methods/attributes I've used. Could I use a "reduced" .h file with only public methods/attributes?
Thanks in advance
__________________________
Fernando de Francisco Cano
__________________________
|
|
|
|
|
|
If you want to ship .H files with a DLL, without giving away any information about what's really in there, the "PIMPL" thing does the trick. Though it's slightly more involved than just shipping a header.
You end up creating 2 headers:
(1) An interface. A header for the public name of your class and public API's in this class. It describes the structure without the meat.
(2) The actual class header, which defines all the stuff, the data, other public and private methods, yada yada yada. This class header also subclasses the interface class. This is referred to as the "implementation".
You must also create a factory method to create your class. It's not acceptable to let the consumer of your DLL do a "new MyClass". This is because the header that you ship him represents only an interface to the class that get's instantiated, and not the actual class.
You must also create a mechanism of destruction. Since the class was created with a factory, and possibly from a different heap than yours -- YOU MUST tell the class to destroy itself. My favorite easy way is to put a virtual "DeleteThis()" method on it.
Here's a quick sample -- in one possible way. (this doesn't match PIMPL exactly -- what an awful name!) But it shows some of the details:
MyClass.H
------------------
class __declspec(dllexport) MyClass<br />
{<br />
public:<br />
virtual int Function1() = 0;<br />
virtual int Function2() = 0;<br />
<br />
virtual void DeleteThis() = 0;<br />
static void MyClass* New();<br />
};
------------------
MyClassImpl.H
---------------------
class __declspec(dllexport) MyClassImpl : public MyClass<br />
{<br />
public:<br />
virtual int Function1() { do something; }<br />
virtual int Function2() { do something else; }<br />
virtual void DeleteThis() {delete this;}<br />
int m_MagicDataThatNoOneCanSee;<br />
<br />
int MagicFunction();<br />
};
---------------------
MyClassImpl.CPP
---------------------
MyClass *MyClass::New()<br />
{<br />
return new MyClassImpl;<br />
}<br />
.....
---------------
---------------------
The gist of this -- is that you hand out interfaces ONLY. The guts that implement the interface can change at will.
This is also one of the foundations of how COM stuff is implemented. They export everything in COM the same way..... With the use of COM you can even play tricks, like creating implementations that actually serve up multiple interfaces.... but's that's another story.
This way of doing things is great. It offers you a lot of flexibility and safety in creating API's!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br />
Peter Weyzen<br />
Staff Engineer<br />
Santa Cruz Networks
|
|
|
|
|
I am currently writing a program to convert an ascii text file into upper/lower case text. The file contains names and addresses, the problem I am having is on the name field. I need to identify if the name is a "special case", ie MR JOHN O'BRIEN -> Mr John O'Brien. There are many examples where this sort of thing happens, can anyone suggest a way of identifying these cases?
Brian Reffold
Programmer
Brown Knight & Truscott
|
|
|
|
|
You're right. I don't think I need transparency at all costs. But it's quite interesting problem, so I'd like to resolve it
-bda-
|
|
|
|
|
You might have to draw your window into a memory device context (not an easy task), and then use AlphaBlend() to draw it with transparency to the screen, but you'll probably need to use multiple AlphaBlend() calls so that you can leave out areas that you don't want transparent. Then draw the non-transparent areas using a simple BitBlt() . A fairly complex thing to do, but I can't see another way of doing it. I would just stick to making the whole window transparent .
Ryan
Being little and getting pushed around by big guys all my life I guess I compensate by pushing electrons and holes around. What a bully I am, but I do enjoy making subatomic particles hop at my bidding - Roger Wright (2nd April 2003, The Lounge)
Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late - John Nichol "Point Of Impact"
|
|
|
|
|
I have created an application that need to fill the screen.
I am able to do it with 1024x768 , but I need it to size correctly if they have their display set to a higher resolution.
i.e 1200x1600 etc.
Does anyone know of a way to do this?
Possibly accessing a systems settings and then using the values returned to set the size of the application.
thanks,
steven
|
|
|
|
|
You can display the window maximized. You don't need to know the actual screen size.
ShowWindow(SW_MAXIMIZED) instead of ShowWindow(SW_SHOW)
-----
We are what we repeatedly do. Excellence, then, is not an act, but a habit.
|
|
|
|
|
That's the easy way most of the time .
I took the view that he wanted to "fill the screen" - including the taskbar area, hence my reply below.
Ryan
Being little and getting pushed around by big guys all my life I guess I compensate by pushing electrons and holes around. What a bully I am, but I do enjoy making subatomic particles hop at my bidding - Roger Wright (2nd April 2003, The Lounge)
Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late - John Nichol "Point Of Impact"
|
|
|
|
|
If you only want it to work with a single-monitor system, then using GetSystemMetrics() with the SM_CXSCREEN and SM_CYSCREEN indexes will give you the width and height of the screen.
If you want it to work with multiple monitors (highly recommended), then it's a bit more complicated. Use EnumMonitors() . Something like this, called from inside your one of your window's functions, probably OnCreate():
BOOL CALLBACK monitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
if(hMonitor != NULL)
{
CWnd *pWnd = (CWnd*)dwData;
if(pWnd != NULL)
pWnd->MoveWindow(lprcMonitor);
}
return TRUE;
}
int CMyWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
...
CDC *pDC = GetDC();
EnumMonitors(pDC->GetSafeHdc(), NULL, monitorEnumProc, (LPARAM)this);
ReleaseDC(pDC);
...
} EnumMonitors() will call the callback function once for every monitor that the specified device context (taken from your window) is on, which may be more than one. However, Windows always creates a top-level window such that it never spans more than one monitor, so from OnCreate() it should only call the callback function once. You can guarantee it's only called once by returning FALSE from the callback function instead of TRUE, if you want to.
Hope this helps. I haven't tested this code, but I've done it before (I just hope my memory is correct )
Ryan
Being little and getting pushed around by big guys all my life I guess I compensate by pushing electrons and holes around. What a bully I am, but I do enjoy making subatomic particles hop at my bidding - Roger Wright (2nd April 2003, The Lounge)
Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late - John Nichol "Point Of Impact"
|
|
|
|
|
exactly what I was looking for ,
thanks,
steven
|
|
|
|
|
Hi,
I have some images that I have to display in many richedit controls. The images are the same and I insert them as Ole Objects. I load the images in the InitInstance method of my application with OleCreateFromFile. Is there any way to form this objects from resource bitmaps in my project?
I want to do this because I now have 10 images and the loading process takes about 10 seconds.
Thanks.
-----
We are what we repeatedly do. Excellence, then, is not an act, but a habit.
|
|
|
|
|
Hi all,
I'm in a quandry! I have multiple CRichEditCrtls on a CScrollView with formatted text. When on the screen, it looks great. When I do a print preview or do a print, the text does not wrap correctly. Each control has the ES_WANTRETURN when they are created.
As an example:
I insert the text: "Now is the time for all good men to come to the
aid of their country."
It looks like this on the screen.
Now is the time for
all good men to
come to the aid of
their country.
This rectangle is located at 100, 100, 213, 170. I then deflate by 5
(so there it is not covering any lines.) The text looks as described
above, all printing/drawing are done in MM_LOENGLISH and when I format
the text I change it to MM_TEXT.
When I calculate the rect (rc member) I do it as:
FORMATRANGE frRange;
memset( &frRange, 0, sizeof( frRange)); //Clear it to zero
frRange.hdc = pDC->m_hDC;
frRange.hdcTarget = pDC->m_hAttirbDC;
frRange.rc.left = ::MulDiv( rect.left, 1440, 100 ); //convert from
0.01" to TWIPS.
... The same for top, right, and bottom...
frRange.rcPage = frRange.rc;
frRange.chrg.cpMin = 0;
frRange.chrg.cpMax = -1;
FormatRange( NULL, FALSE );
int iTextLength = GetTextLength();
int iCurrPos = 0;
while(( iCurrPos = FormatRange( &frRange, TRUE )) < iTextLength )
{
frRange.chrg.cpMin = iCurrPos;
frRange.rc.top = frRange.rc.bottom;
frRange.rc.bottom = frRange.rcPage.bottom;
}
FormatRange( NULL, FALSE );
This is all fine, except the output looks like:
Now is the time
for all good men
aid come to the aid
of their country.
You see that the first line broke before the for instead of after and
this throws everything else off...
My question is how do I calculate the bounding rect?
BTW, I have tried
frRange.rc.left = ::MulDiv( rect.left, 1440, pDC->GetDeviceCaps(
LOGPIXELSX ));
AND
frRange.rc.left = ::MulDiv( rect.left, 1440, ::GetDeviceCaps(
pDC->m_hDC, LOGPIXELSX ));
Since the pDC->GetDeviceCaps( index ) uses the m_hAttribDC instead of
the m_hDC handle.
I'm wondering if it has to do with the fact that in
MM_LOENGLISH, one logical unit = 0.01" and in MM_TEXT, one
Logical unit = one device Pixel? This is where I think I'm having the problem.
So, what I was thinking is that:
0.01" = one device Pixel (on this display that is 96 DPI)
... 0.01" = 1/96 DPI
Now my train of thought goes out the window (no pun!)
I'm needing some advice from you experts out there
Thanks
Larry
|
|
|
|
|
So, I have ya'll stumped huh?
Larry
|
|
|
|
|
Hi,
I want to process data from an edit control by pressing "enter" but I don't know how I I can "tell" the programm that the enter button has been pushed. Can anybody help me with this? Maybe there is an easy way to do this, I tried the WM_CHAR or WM_KEYDOWN without success. Maybe someone can give me a link to the propper tutorial or wirte a few lines.
Thanks in advance
|
|
|
|
|
read down a bit further, there's an answer for you ... using PreTranslateMessage.
Maximilien Lincourt
For success one must aquire one's self
|
|
|
|
|
PreTranslateMessage is a big hammer that gets recommended probably too often. It's also not too easy to write - it tends to end up as spaghetti code.
When you have a dialog box, you first ask the dialog box if it wants to handle messages, by calling ::IsDialogMessage() for a modeless dialog. This is done automatically by the modal message loop for a modal dialog. MFC 'modal' dialogs are in fact modeless Win32 dialogs - you can see this in CDialog::DoModal(). CDialog::PreTranslateMessage() calls ::IsDialogMessage() for you.
When you press certain keys (TAB, Enter, Escape) ::IsDialogMessage() performs the operation you requested and returns FALSE so that the message isn't dispatched by TranslateMessage()/DispatchMessage().
In order to allow the controls to override this behaviour, ::IsDialogMessage() sends a WM_GETDLGCODE message to the control with the focus. You can handle this message in a subclass window procedure in order to catch the return key - from memory, you should call the original window procedure, OR in the DLGC_WANTMESSAGE flag and handle the message directly in the WM_GETDLGCODE handler.
This has two advantages: this behaviour works in a standard Win32 app (no MFC) without having to add a lot of extra plumbing, and for MFC apps, you can create a class derived from CEdit that has this behaviour and reuse that class elsewhere.
The built-in MFC OnGetDlgCode() handler isn't very helpful for DLGC_WANTMESSAGE, because it doesn't allow access to lParam (which points to the MSG structure). To handle this properly, don't use the ON_WM_GETDLGCODE() message map entry - use ON_MESSAGE, as defined in MFC Technical Note 6 (look for TN006 in the MSDN Library index).
--
Mike Dimmick
|
|
|
|
|
In the Message Map of your window/dialog you have to add:
ON_NOTIFY(EN_MSGFILTER, IDC_YOUR_EDIT_ID, OnEnMsgfilterCompose)
The OnEnMsgfilterCompose looks like this:
OnEnMsgfilterCompose(NMHDR *pNMHDR, LRESULT *pResult)
In it do this:
MSGFILTER *pMsgFilter = reinterpret_cast<msgfilter *="">(pNMHDR);
if (pMsgFilter->wParam == VK_RETURN) { // this is the "enter"
}
-----
We are what we repeatedly do. Excellence, then, is not an act, but a habit.
|
|
|
|
|
I created a CDHtmlDialog based dialog and I wanna get content of a Text Field html element so I wrote this code.
<br />
HRESULT CMyHtmlDlg::OnTest(IHTMLElement* pElement)<br />
{<br />
IHTMLElement* pTextElement = NULL;<br />
if (GetElement(_T("Text1"), &pTextElement) == S_OK && pTextElement != NULL)<br />
{<br />
pTextElement->put_innerText(_bstr_t("majid"));<br />
CString str;<br />
BSTR bstrText;<br />
pTextElement->get_innerText(&bstrText);<br />
str = bstrText;<br />
}<br />
return S_OK;<br />
}<br />
the put_innerText function works properly but
get_innerText function doesn't get content of TextField and bstrText set to <bad Ptr>.
so how could I solve this problem?
Thank u in advance
|
|
|
|
|
See if changing BSTR bstrText to CComBSTR bstrText helps.
|
|
|
|
|
I don't have an intimate knowledge of the finer points of macro expansion, but these look suspicious to me, and I am wondering if they will cause problems:
#define ABC 120<br />
#define HALF_ABC ABC / 2<br />
#define QUART_ABC ABC / 4 // this is one-quarter
The first one is normally what I expect to see as a simple substitution. The second one is an operation. The third is an operation with a trailing comment. Will these be expanded properly if used as follows:
for (int i = 0; i < QUART_ABC; ++i)<br />
{<br />
if (i >= HALF_ABC)<br />
}
Besides converting all of these to const ints, what is a
better way to make sure they do what is intended? The software appears to be working properly, but those last pesky hard-to-find bugs may be in these areas.
Dave
"You can say that again." -- Dept. of Redundancy Dept.
|
|
|
|
|
Based on the fact that the preprocessor replaces the #define constants with what you have defined them as right inline, you should always surround compound #define values with parenthesis. EX:
#define ABC 120
#define HALF_ABC (ABC / 2)
#define QUART_ABC (ABC / 4)
This way, they will be evaluated the way that you intended, rather than the way that the expanded expression evaluation order dictates. EX:
for (int i = 0; i < QUART_ABC; ++i)
{
if (i >= HALF_ABC)
// ... processing
}
with your code as is really gets preprocessed into the following:
for (int i = 0; i < 120 / 4; ++i)
{
if (i >= 120 / 2)
// ... processing
}
when it properly should be:
for (int i = 0; i < (120 / 4); ++i)
{
if (i >= (120 / 2))
// ... processing
}
|
|
|
|
|
Thanks. I guess I don't see much difference between
for (i=0; i < 120/4; ++i)
and
for (i=0; i < (120/4); ++i)
But, in an earlier thread below, I do see problems for
#define ABC 120
#define ABC_LESS ABC - 50
i = 100 - ABC_LESS;
simply because of the order of evaluation with addition and subtraction, where we would get
i = 100 - 120 - 50
rather than
i = 100 - (120 - 50)
"You can say that again." -- Dept. of Redundancy Dept.
|
|
|
|
|
As a rule, I put parens around everything that I #define. Even strings.
#define FRED ("fred")
#define X (2)
If you get bitten by that bug once, you never want to chase that bug again.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br />
Peter Weyzen<br />
Staff Engineer<br />
Santa Cruz Networks
|
|
|
|
|
#define ABC 120
This is fine.
#define HALF_ABC ABC / 2
This will work most of the time, but could come back to bite you. You almost certainly want:
#define HALF_ABC (ABC / 2)
#define QUART_ABC ABC / 4 // this is one-quarter
You have the same problem as before, and could use brackets. The comment is dealt with by the preprocessor, and earlier than macro expansion in my experience, so its as if you hadn't typed it.
Iain.
|
|
|
|
|