|
Stephen,
About a year ago I set up a system very similar to what you are looking for. I created an abstract base class that defined the entire interface that I needed for the main program, then created a series of DLLs that implemented specific instances of the class.
Quick code :
class Base { // in file "Base.h", included into each DLL
public:
virtual void showMsg(string msg);
virtual string translateMsg(string msg);
};
Then create a "German.DLL"
...
class German : public Base {
public:
virtual void showMsg(string msg) { ... }
virtual strin translateMsg(string msg) { ... }
};
__declspec ( dllexport) Base* create();
...
And create a "French.DLL"
...
class French : public Base {
public:
virtual void showMsg(string msg) { ... }
virtual string translateMsg(string msg) { ... }
};
__declspec ( dllexport) Base* create();
...
In the main program :
...
void (create*)();
HMODULE lib;
// Create the required type of language by loading DLL and finding 'create' function
Base* language_;
switch (type) { // assume we have varialbe 'type' which tells us what we want
case GERMAN :
lib = LoadLibrary("German.dll");
create = GetProcAddress(lib,"create");
language = create();
break;
case FRENCH :
lib = LoadLibrary("French.dll");
create = GetProcAddress(lib, "create");
break;
}
language = create();
// and Use
string msg = language->translateMsg("Hello");
language->showMsg(msg);
...
This approach only works if the main prgram NEVER needs to call a class specific function - it can only ever call functions declared in the "base" class. It also has the advantage that you only need to export a single function from each DLL - the 'object factory'. This is all very similar in concept to COM, but much simpler to code. COM would be preferable if the application was (or could) be in another programming language.
You don't need to use extension DLLs - the differences are mainly to do with resource management. Unless you have a specific need, then 'standard' dlls will work fine.
Syntax is probably a bit rusty in the sample code. Hope this helps.
-------------------------
Reg : "Well, what Jesus blatantly fails to appreciate is that it's the meek who are the problem."
|
|
|
|
|
Thanks Mike, this looks like just what I need. As far as I understand, what I am trying to do is conceptually similar to COM, but I'm trying to get away without having to learn a whole new system, because I only want to use C++. Your approach will work because indeed the main program will only ever call a restricted, pre-determined set of functions defined in the base class.
So you say I don't need to use extension DLLs? Even if the Base class (from your example) is derived from CObject? And maybe some of the parameters of the derived functions will take pointers to MFC classes?
The reason I ask is the following from the documentation: "If you need to pass an MFC or MFC-derived object pointer to or from an MFC DLL, the DLL should be an extension DLL. The member functions associated with the passed object exist in the module where the object was created. Since these functions are properly exported when using the shared DLL version of MFC, you can freely pass MFC or MFC-derived object pointers between an application and the extension DLLs it loads." (from the "Extension DLLs" page of the VC++ docs.)
Is this not relevant to my case? If you could briefly explain, it would be very helpful.
thanks again,
best,
Stephen
|
|
|
|
|
Stephen,
I'd be lying to you if I said I understand the whole 'extension DLL' concept. I have read the same documentation you are quoting from, and it's obviously poorly written - it's quite common to derive objects from CObject and pass them into and out of DLLs. I do it all the time with CDialog derived classes. My guess is that this particular piece of documentation was written before (or without the knowledge of!) the whole "AFX_MANAGE_STATE" concept, which seems to be the key to allowing a 'regular' MFC DLL to import and export CObjects. The main difference (as far as I can see) between an extension DLL and a regular DLL is in the handling of resources. A regular DLL has it's own private resources - a dialog with an ID of "1000" can exist in two separate regular DLLs, and there will be no problems (provided the "AFX_MANAGE_STATE" rules are followed!). In an extension DLL, the resources are 'appended' to the apps resources, so you can get conflicts with ID ranges, etc.
There are also issues to be dealt with when mixing MFC objects and threading, so if a DLL wants to create it's own threads you need to be very careful in passing certain MFC objects between DLLs.
----------------
Reg : "Well, what Jesus blatantly fails to appreciate is that it's the meek who are the problem."
|
|
|
|
|
I am having some trouble with CFindAndReplace dialog. It appears that everything works until the point the dialog goes out of scope when it crashes.
According to documents, you have to instantiate the structure on the heap and then create the dialog which is what i do :
void LogDlg::OnCmdSearch()
{
if (!pFRDlg)
{
// Initialize find string
if (!szFRDlgFindString)
{
szFRDlgFindString = new char[256];
szFRDlgFindString[0] = 0;
}
// New find dialog
pFRDlg = new CFindReplaceDialog();
pFRDlg->m_fr.lStructSize = sizeof(pFRDlg->m_fr);
pFRDlg->m_fr.hwndOwner = this->GetSafeHwnd();
// Can't do up/down searches in RichEditCtrl?
pFRDlg->m_fr.Flags |= FR_HIDEUPDOWN;
pFRDlg->m_fr.lpstrFindWhat = szFRDlgFindString;
pFRDlg->m_fr.wFindWhatLen = 256;
pFRDlg->Create(TRUE, "", NULL, FR_DOWN, this);
}
}
After that, you have your search routine:
void LogDlg::OnFind()
{
if (pFRDlg->IsTerminating())
{
pFRDlg = NULL;
}
else if (pFRDlg->FindNext())
{
static bool InFindNext = false;
if (InFindNext)
return;
InFindNext = true;
CRichEditCtrl *pEdit = (CRichEditCtrl *)GetDlgItem(IDC_LOGVIEW);
FINDTEXTEX FindText;
pEdit->GetSel(FindText.chrg);
// Set text range appropriately....
// If it's empty, select the entire range
if (FindText.chrg.cpMin == FindText.chrg.cpMax)
{
FindText.chrg.cpMin = 0;
FindText.chrg.cpMax = -1;
}
// If there's selected text, read past it.
else if (FindText.chrg.cpMin >= 0 && FindText.chrg.cpMax > 0)
{
FindText.chrg.cpMin = FindText.chrg.cpMax;
FindText.chrg.cpMax = -1;
}
FindText.lpstrText = szFRDlgFindString;
for (;;)
{
// Did we find something?
if (pEdit->FindText((pFRDlg->MatchCase() ? FR_MATCHCASE : 0) |
(pFRDlg->MatchWholeWord() ? FR_WHOLEWORD : 0),
&FindText) != -1)
{
pEdit->SetSel(FindText.chrgText);
break;
}
// Looped?
else if (FindText.chrg.cpMin != 0 || FindText.chrg.cpMax != -1)
{
if (MessageBox(_T("End of text reached. Search again from the beginning?"), _T("Selection not found."), MB_YESNO | MB_ICONQUESTION) == IDYES)
{
FindText.chrg.cpMin = 0;
FindText.chrg.cpMax = -1;
}
else
break;
}
// Nowhere in there
else
{
MessageBox(_T("No matching text found."), _T("Selection not found"), MB_OK | MB_ICONWARNING);
pEdit->SetSel(0, 0);
break;
}
}
InFindNext = false;
}
}
So, what else do i need to do, to prevent this thing from crashing? Do I need to clean up this thing somewhere? Am i missing something?
|
|
|
|
|
I want to have a certain control about ALL running windows of Internet Explorer.
For example I want to do my own things with the adress, if the user types in e.g. "g Something" (without quotation-marks), I want to navigate the browser to www.google.com and then search for "Something". (same as the browser Opera does)
How can I do this?
thanks in advance
|
|
|
|
|
Hi,
I'm working with a bitmap that is 1 bit. I need to find out if each bit is a 0 or a 1. Basically, I'm reading it in, one scan line at a time, for this example, let's say that it is 277 bytes wide. I do the following:
char* imageBytes = new char[277];
file.Read(imageBytes, 277);
for(int x = 0, x < 277; x++)
{
int indByte = imageBytes[x];
}
Can anyone help me to access each one of the bits to find out if it's black or white?
Thanks for any help you can provide,
Craig
|
|
|
|
|
once you have the byte that holds the bit-in-question, you need to do some old-school bit masking:
int iBitPos = 7 - (uPixelX - (uPixelX / 8) * 8);
BYTE masks[8];
for (int z=0;z < 8;z++)
{
masks[z] = 1 << z;
}
bool bitIsOn = (inByte & masks[iBitPos]) != 0;
-c
------------------------------
Smaller Animals Software, Inc.
http://www.smalleranimals.com
|
|
|
|
|
Chris,
Thanks for the reply. I tried pretty much all day yesterday to get this to work for my situation and was unsuccessful. I ended up doing something real slow and at I'm sure a VERY beginners level but I got it to work. I was wondering if you could take a look and tell me if there is a way to optimize it at all. Following is the code that I'm using:
file.SeekToBegin();
int scanLine = 4 * ((pbmih->biWidth * pbmih->biBitCount + 31) / 32);
BYTE* buffer = new BYTE[scanLine];
int bytesread;
file.Seek(hdr.bfOffBits, 0);
FILE* output;
output = fopen( "..\\images\\output.txt", "a+" );
fclose(output);
bytesread = file.Read(buffer, scanLine);
CString strOut;
while(bytesread)
{
int arrayBytes[8];
for (int ff=0;ff<8;ff++)
arrayBytes[ff]=0;
strOut.Empty();
for(int x = 0; x < scanLine; x++)
{
BYTE inByte = buffer[x];
for (int ff=0;ff<8;ff++)
arrayBytes[ff]=0;
BYTE byteone;
BYTE bytetwo;
byteone = inByte >> 4;
bytetwo = inByte << 4;
bytetwo = bytetwo >> 4;
switch (byteone)
{
case 0x1:
arrayBytes[4]=1;
break;
case 0x2:
arrayBytes[5]=1;
break;
case 0x3:
arrayBytes[4]=1;
arrayBytes[5]=1;
break;
case 0x4:
arrayBytes[6]=1;
break;
case 0x5:
arrayBytes[4]=1;
arrayBytes[6]=1;
break;
case 0x6:
arrayBytes[5]=1;
arrayBytes[6]=1;
break;
case 0x7:
arrayBytes[4]=1;
arrayBytes[5]=1;
arrayBytes[6]=1;
break;
case 0x8:
arrayBytes[7]=1;
break;
case 0x9:
arrayBytes[4]=1;
arrayBytes[7]=1;
break;
case 0xA:
arrayBytes[5]=1;
arrayBytes[7]=1;
break;
case 0xB:
arrayBytes[4]=1;
arrayBytes[5]=1;
arrayBytes[7]=1;
break;
case 0xC:
arrayBytes[6]=1;
arrayBytes[7]=1;
break;
case 0xD:
arrayBytes[4]=1;
arrayBytes[6]=1;
arrayBytes[7]=1;
break;
case 0xE:
arrayBytes[5]=1;
arrayBytes[6]=1;
arrayBytes[7]=1;
break;
case 0xF:
arrayBytes[4]=1;
arrayBytes[5]=1;
arrayBytes[6]=1;
arrayBytes[7]=1;
default:
;
}
switch (bytetwo)
{
case 0x1:
arrayBytes[0]=1;
break;
case 0x2:
arrayBytes[1]=1;
break;
case 0x3:
arrayBytes[0]=1;
arrayBytes[1]=1;
break;
case 0x4:
arrayBytes[2]=1;
break;
case 0x5:
arrayBytes[0]=1;
arrayBytes[2]=1;
break;
case 0x6:
arrayBytes[1]=1;
arrayBytes[2]=1;
break;
case 0x7:
arrayBytes[0]=1;
arrayBytes[1]=1;
arrayBytes[2]=1;
break;
case 0x8:
arrayBytes[3]=1;
break;
case 0x9:
arrayBytes[0]=1;
arrayBytes[3]=1;
break;
case 0xA:
arrayBytes[1]=1;
arrayBytes[3]=1;
break;
case 0xB:
arrayBytes[0]=1;
arrayBytes[1]=1;
arrayBytes[3]=1;
break;
case 0xC:
arrayBytes[2]=1;
arrayBytes[3]=1;
break;
case 0xD:
arrayBytes[0]=1;
arrayBytes[2]=1;
arrayBytes[3]=1;
break;
case 0xE:
arrayBytes[1]=1;
arrayBytes[2]=1;
arrayBytes[3]=1;
break;
case 0xF:
arrayBytes[0]=1;
arrayBytes[1]=1;
arrayBytes[2]=1;
arrayBytes[3]=1;
break;
default:
;
}
for (int z=7;z>=0; z--)
{
char buf[10];
itoa(arrayBytes[z], buf, 10);
buf[1]='\0';
output = fopen( "..\\images\\output.txt", "a+" );
fseek(output, 0L, SEEK_END );
fprintf(output, "%s", buf);
fclose(output);
}
}
output = fopen( "..\\images\\output.txt", "a+" );
fseek(output, 0L, SEEK_END );
fprintf(output, "\n");
fclose(output);
bytesread = file.Read(buffer, scanLine);
}
fclose(output);
delete buffer;
delete pbmih;
file.Close();
Thanks for any insight you can provide,
Craig
|
|
|
|
|
You can do the following
for (int i = 0; i < 8; i++)
{
BOOL fSet = (indByte >> i) & 1;
}
modified 29-Aug-18 21:01pm.
|
|
|
|
|
I found the StillCap demo and it has the annoying p[roperty ofg displaying a running counter of frames(?) in the preview window. I've looked everywhere I can think of to look, and I can't find where to turn this damn thing (the running frame counter) off.
Can someone please direct me as to where to look?
|
|
|
|
|
Hi
I just searched the whole CodeProject site but didn't find the article I was searching for. The app (and its source) what I search for was able to intercept the string the user types in the editbox from startmenu -> "Run"
I hope this is enough information,
please help me
|
|
|
|
|
|
Hi,
I'm writing an app using WTL (love it!) but I'm finding a problem. Whe the user clicks on the Zoom In icon in the toolbar (or menu), I want to change the mouse cursor to my custom magnifying glass cursor. The problem is that nothing was happening.
After a little investigation and tinkering, I hooked my app up so that if I click the left mouse button it would change the cursor. This works -- but if I let go of the mouse button, or I move the mouse, it goes back to the arrow. I stepped through the code and it is loading the cursor resource with no problem... it just won't stay.
I have tried both ::SetCursor and CWaitCursor (true, MAKEINTRESOURCE(...), false) to no avai. I do not change the cursor elsewere.
Any help would be appreciated, thanks
---
PAGE FAULT: Please insert "Swap File Disk 2" in drive and press any key to continue
|
|
|
|
|
What you are seeing is the WM_SETCURSOR setting the cursor back to the registered cursor for your main window.
The easiest thing to do it in your main window, override WM_SETCURSOR. If LOWORD (lParam) == HTCLIENT then set the cursor to the cursor you want. Otherwise, set bHandled to false and let the default processor handle the message.
Tim Smith
Descartes Systems Sciences, Inc.
|
|
|
|
|
You sir, are absolutely correct! Thank you very much
---
PAGE FAULT: Please insert "Swap File Disk 2" in drive and press any key to continue
|
|
|
|
|
Hello,
I have a dialog type application and I had to manually set the size of the dialog and the size and position of all my controls using:
GetDlgItem(IDC_STATIC_COUNT_BORDER)->SetWindowPos(NULL,12,96,122,55,NULL);
The problem I am having is that my tab order is now messed up. Do I need to SetWindowPos() in a specific order to maintain my tab order? I set the tab order through visual studio and it seems that the tab order is now backwards.. Has anyone seen this?
Thanks,
Rob
|
|
|
|
|
Never mind I figured it out.. just incase anyone else has the problem it appears that when you do the SetWindowPos() on all your controls the bottom setwindowpos is your first tab and second from the bottom is you second and so on.....
|
|
|
|
|
To preserve Tab Order (which is the same as Z-order) you should use the flag SWP_NOZORDER when calling SetWindowPos().
Paolo
------
"airplane is cool, but space shuttle is even better" (J. Kaczorowski)
|
|
|
|
|
Thanks!! I'll implement that flag and use the tab order through visual studio.
Rob
|
|
|
|
|
How can I (programatically) scroll the client area of an application derived from CHtmlView. Although CHtmlView is derived from CScrollView but ScrollToPosition(), , SetScrollInfo(), ScrollWindow() and ScrollWindowEx() functions are not working.
I have seen a bug info BUG: Calling ScrollToPosition() in CFormView Derived Class Moves the Scroll Bars but Not the Window but i think its for Window CE only. Is it a similar kind of problem here?
Please help, i want to programatically scroll the client area of my application derived from CHtmlView.
Thanks
Umar Riaz
RIT Research Corporation,
Rochester, NY 14580
(716) 239-6064 (Office)
(716) 317-1786 (Cell)
(716) 216-2294 (Home)
|
|
|
|
|
I have a multi-threaded windows application
running on NT 4.0. Its actually based on a
class I found here called CThreadJob. It
continually performs an ODBC lookup and
displays the results. Pretty routine stuff.
If I build it, then launch it from explorer, it
seems to work fine. However, if I launch it
from within the Visual Studio IDE, in debug
or release mode, using F5 or Ctrl-F5, the
application deadlocks immediately and I
have to reboot to remove it (the rest of
the system is okay, I just can't get control
of the IDE or the app - even Task Manager
can't kill it).
I know this is sketchy and a really tough
one to diagnose remotely, but perhaps
someone has had a similar problem and
could give me something to look for. I
could swear this program is as thread
safe as they come, but the IDE seems
to feel otherwise.
jb
|
|
|
|
|
The first thing that comes to mind is that when you launch it in debug mode from the VS context, the exe is run from the \debug directory and also, the working directory is different and there might be different command line params set from the VS IDE.
I program multi-threaded apps every day (my job is programming servers) and the best way to find deadlocks is to add extensive logging to your application.
Put logs before and after every one of your wait functions (WaitForSingleObject, WaitForMultipleObjects, etc..) then see where the deadlock is.
Another thing that comes to mind when debugging multi-threaded applications is timing. The timing is completely different in debug mode than it is in release and deadlocks are all about timing.
Maybe the deadlock bugs are there, but they do not happen in release mode since it is faster and it catches up better.
Hope this helps,
Jeremy.
GFI
"Hey man, Taliban, Tali me Banana."
|
|
|
|
|
Hello,
i have a activex control.
it is only a treeviewctrl using wtl.
now i implemented a contextmenu handler, but if i
clicked on a menu point nothing happens.
in my message map i have:
COMMAND_ID_HANDLER (ID_OF_MENU_POINT, OnMyMenu)
What is my mistake?
|
|
|
|
|
Where is your message handler, in the treeview? Have you chained the context menu messages?
|
|
|
|
|
The massage handler is in my COM class (header file).
class ATL_NO_VTABLE CMyClass :
public CComObjectRootEx<ccomsinglethreadmodel>,
public CComCompositeControl<cmyclass>,
.....
BEGIN_MSG_MAP(CMyClass )
CHAIN_MSG_MAP(CComCompositeControl<cmyclass>)
......
......
MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
COMMAND_ID_HANDLER(ID_CHECKSERVER,OnDelete)
COMMAND_ID_HANDLER(ID_CHECK,OnDel)
END_MSG_MAP()
LRESULT OnDelete(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
MessageBox("asdsdasd");
return S_OK;
}
What do mean with chaining the messages?
|
|
|
|
|