|
Hi
I have been trying to write a dialog dll and have been having some real issues with it see (DLL and CTypedPrtList problem[^]). It seems to have moved away from my initial concerns of using CTypedPtrList in the DLL to a more general issue hence the new post.
I stripped the code down to the bare minimum removing all the interesting stuff and it still fails if I OK out of the dialog but not if I Cancel. To recap on the application.
void CTestApp::OnFileOpen() <br />
{<br />
CLantisPatientSelectDlg dlg;<br />
<br />
if(dlg.DoModal() == IDOK){<br />
m_nPatID1 = dlg.GetPatID1();<br />
}<br />
}
CLantisPatientSelectDlg is implemented in the DLL with exported constructors, DoModal() and GetPatID1() member functions.
void CLantisPatientSelectDlg::OnOK() <br />
{<br />
int nIndex;<br />
CPatientDetails *pPatientDetails;<br />
CListCtrl *pList = (CListCtrl *)GetDlgItem(IDC_PATIENTLIST);<br />
<br />
nIndex = pList->GetSelectionMark();<br />
if(nIndex != -1){<br />
} else {<br />
m_nSelectedPatID1 = -1;<br />
}<br />
<br />
m_bTerminateLoad = true;<br />
::WaitForSingleObject(m_hListLoadingThread,INFINITE);<br />
<br />
CDialog::OnOK();<br />
}<br />
<br />
void CLantisPatientSelectDlg::OnCancel() <br />
{<br />
m_bTerminateLoad = true;<br />
::WaitForSingleObject(m_hListLoadingThread,INFINITE);<br />
<br />
CDialog::OnCancel();<br />
}
Now I have done some debugging on this and it appears that when the program goes through the OnOK() function the line
m_nSelectedPatID1 = -1;
corrupts the "this" pointer of the CTestApp class such that when I get back into the OnFileOpen() function the m_nPatID1 = dlg.GetPatID1(); fails.
Looking at the memory allocation somehow the m_nSelectedPatID1 variable and the "this" pointer are using the same memory and hence setting the variable to -1 in the DLL gives a pointer which is nonsense.
Now why is this happening?
I am using two header files for the CLantisPatientSelectDlg. One for build the DLL which needs to know about all the internal stuff and another for building the application which only has the exported functions in it. Reasoning being that the users don't need to know all that internal stuff plus it means they also don't need to have other header files detailing the other classes that the dialog uses to hold it data etc.
So I have
CLantisPatientSelectDlg.h
class AFX_EXT_CLASS CLantisPatientSelectDlg : public CDialog<br />
{<br />
public:<br />
int GetPatID1();<br />
CLantisPatientSelectDlg(CWnd* pParent = NULL);
virtual ~CLantisPatientSelectDlg();
<br />
enum { IDD = IDD_SELECTPATDLG };<br />
<br />
<br />
public:<br />
virtual int DoModal();<br />
protected:<br />
virtual void DoDataExchange(CDataExchange* pDX);
<br />
protected:<br />
void DeletePatientList();<br />
int m_nSelectedPatID1;<br />
HANDLE m_hListLoadingThread;<br />
static UINT LoadList(LPVOID pParam);<br />
bool m_bTerminateLoad;<br />
<br />
virtual BOOL OnInitDialog();<br />
afx_msg void OnDblclkPatientlist(NMHDR* pNMHDR, LRESULT* pResult);<br />
virtual void OnOK();<br />
virtual void OnCancel();<br />
afx_msg void OnSortByName();<br />
afx_msg void OnSortByNum();<br />
afx_msg void OnShowAll();<br />
afx_msg void OnShowActive();<br />
afx_msg void OnShowOnTX();<br />
DECLARE_MESSAGE_MAP()<br />
};
and CLantisPatientSelectDlgInt.h
class AFX_EXT_CLASS CLantisPatientSelectDlg : public CDialog<br />
{<br />
public:<br />
int GetPatID1();<br />
CLantisPatientSelectDlg(CWnd* pParent = NULL);
<br />
public:<br />
virtual int DoModal();<br />
};
Now I played around with this this morning and I found that if I add a
protected:<br />
int m_nSelectedPatID1;
section to the second header file (ie the one for application builders to use) then the application works and both routes out of the dialog work and my "this" pointer doesn't get corrupted.
So have I answered my own question. I'm not sure
- I thought I could use different header files. Can I? If so how do I do it safely.
- why does the memory management go wrong. I have read something about the possibility of the system using two different memory managers that don't know what the other one is doing. How do I check this and what do I do to ensure it is not happening.
Can someone point me to a good guide about this type of DLL construction.
Many thanks and sorry for the long post. If you have got this far I appreciate your endurance.
Andrew Hoole
|
|
|
|
|
Ah - I see what happened now.
I ran into the same problem years ago. I wasn't intentionally using different headers but by mistake ended up doing something very similar.
I'm sure someone else can give you a more detailed explanation of this but the short story is that the address of your ID is off into a bogus area due to the multiple header files.
I think if you really need to be able to do this, you need to setup some dummy variables so that both of the headers represent a class with the same layout/size. I'm still not sure if it is going to work in that case but I do know from experience that using multiple headers holding different variables will cause big problems. Sorry I can't give more/better info.
|
|
|
|
|
Yeah I think I am going to have to use the same header file but when I tried it earlier I get compiler errors on the
enum { IDD = IDD_SELECTPATDLG };<br />
section of the header because that is declared in the resource.h file of the dll and not the resource.h file of the application.
Is it a problem if several of these IDs resolve to the same number?
I would have thought that the layout/size of the class would have been held in one of the compiled files that are used by the linker so something.
|
|
|
|
|
Ok I have now included the resource.h file in the CLantisPatientSelectDlg.h file and now the whole thing(including the important bits I had removed for debugging purposes) compiles and runs fine.
So now I just need to find out how I can use different header files without getting this trouble as it seems the only way to hide from the user all the mess of the implementation.
Thanks for all the help and comments so far.
Andrew Hoole
|
|
|
|
|
How to hide mess from user:
1. Implement a data structure that has the data you need to and from the dialog. Share this data structure in a header between the main program and the support DLL. Program passes pointer to valid memory block representing data structure to exported DLL function.
2. Also pass HWND of parent window into exported function. This way, your C++ object does not have to cross the DLL boundary. Wihtin the DLL you cna make a temporary CWnd and 'attach' the passed in HWnd to it. Remember to Detach ont he way out.
Now you don't have to 'expose' any more details than necessary and almost all, if not all, of your problems are solved.
The advantage here, is you can actually make your entire MFC Dialog DLL code compatible with a regular Win32 program if done correctly - static link MFC, use the proper AFX macros, etc.
Trying to export a 'fraction' of a dialog's class from the DLL will only get you into more trouble than it is worth. You are not ending up with the proper offsets to member variables, virtual functions, etc. I would stay clear of any 'cute' skinning or other 'framework' system that relies on such a method.
|
|
|
|
|
Are you saying that I should wrap my DLL dialog class in another class with a simple interface. Otherwise I can't see how what you are suggesting gets me away from having to have the header file of my DLL dialog exposed to the users.
Using the HWND idea - would that mean I don't create a direct instance of the DLL dialog class as I have done but rather pass the HWND into a simple function which then attachs to it and creates the dialog class internally.
Sorry I am not being very bright here but thanks for the help.
|
|
|
|
|
Sorry, option 2 is the one I meant.
When you pass in the HWND of the 'parent' window to the function, you attach this passed HWND to an internal CWnd object, and that CWnd can be the 'parent' for your internal dialog class. After DoModal returns and you collected up all the data, you can detach the temporary CWnd from the passed HWND.
This way, the entire interface into the DLL to 'call' the dialog is a pointer to your data structure and an HWND. You only need to give the user a header file with the definition of your data structure and a function prototpye - the function exported from your DLL.
I do this all the time to get InstallShield or legacy Win32 applications to be able to call MFC dialogs.
|
|
|
|
|
Hi all,
I'm a complete novice to C++.net and I'm in a spot of bother. I have some values that require certain calculations and conversions which I have no problem with at all. My problem arises when I try to store the values as hex strings. So, for example, I have a byte holding the value (in dec) 252. I want to hold the value as its hex equivalent in a string which will later be displayed in a textbox.
Does vs.net provide any built in functions for this task or, if not, how would I go about the conversion manually?
Any help gratefully recieved.
|
|
|
|
|
char c = 252;
CString str;
str.Format("0x%X", c);
there, str contains the string "0xFC"
you could also use sprintf() and so on...
TOXCCT >>> GEII power [toxcct][VisualCalc]
|
|
|
|
|
I tried that already and just get the following error,
error C2664: 'System::String __gc *System::String::Format(System::String __gc *,System::Object __gc *)' : cannot convert parameter 2 from 'int' to 'System::Object __gc *'
Conversion from a built-in type or a value type to 'System::Object __gc*' requires boxing
|
|
|
|
|
oh, your programming managed code.
well, what about this ?
char c = 252;
char str[100];
ssprintf(str, "0x%X", c);
TOXCCT >>> GEII power [toxcct][VisualCalc]
|
|
|
|
|
What I need to do is store the hex value as a string so I can set a textbox text element to that string. So I'm looking to do something like
<br />
System::Byte b = 252;<br />
System::String* s = b (formatted as hex value);<br />
then
<br />
textBox1->Text = s;<br />
Does any of that make sense??
|
|
|
|
|
toxcct wrote:
ssprintf(str, "0x%X", c);
Shouldn't that be:
sprintf(str, "%#X", c);
"Ideas are a dime a dozen. People who put them into action are priceless." - Unknown
|
|
|
|
|
for ssprintf -> sprintf, yes, i made a mistake
for 0x%X -> %#X, it is as you prefer...
TOXCCT >>> GEII power [toxcct][VisualCalc]
|
|
|
|
|
Hi Dear,
Just do the following
byte _val;
char _data[4]="";
sscanf(_data,"%x",&_val);
Regards
~Kid
|
|
|
|
|
itkid wrote:
sscanf(_data,"%x",&_val);
Perhaps you meant sprintf() instead of sscanf() .
"Ideas are a dime a dozen. People who put them into action are priceless." - Unknown
|
|
|
|
|
Sorry still not working, getting the following,
error C3861: 'sprintf': identifier not found, even with argument-dependent lookup
if I use sscanf, same error with obvious replacements.
|
|
|
|
|
The sprintf() function is part of stdio.h. I do not know if that set of APIs is available with VS.Net.
"Ideas are a dime a dozen. People who put them into action are priceless." - Unknown
|
|
|
|
|
Can't seem to get it to work at all tbh. But eh, what do I know?
Surely .net must provide some way to format a string to dispay value in hex. Or you would think so!!
|
|
|
|
|
|
Christian Graus might have a few articles in this regard.
"Ideas are a dime a dozen. People who put them into action are priceless." - Unknown
|
|
|
|
|
I'll give it a go.
Cheers everyone for the help!
|
|
|
|
|
Hi,
I have to create a CMap and store N number of (CString,int)
and i want to look up using CString and return value would be int.
If any body have gone through this requirement pls let me know.
i am new to CMap.If anyother method exist also welcome.
regards
Chezhian
|
|
|
|
|
<br />
#include <afxtempl.h><br />
<br />
CMap<CString, LPCTSTR, int, int> myMap;<br />
<br />
myMap.SetAt("one", 1);<br />
myMap.SetAt("two", 2);<br />
myMap.SetAt("three", 3);<br />
<br />
int nValue = 0;<br />
if (myMap.Lookup("two", nValue))<br />
{<br />
TRACE(_T("value is %d\n"), nValue);<br />
}<br />
Pssst. You see that little light on your monitor? That's actually a government installed spy camera. Smile and wave to big brother!
|
|
|
|
|
hi,
I tried this.
It gives the following errors
'myMap':UnKnown size
'myMap':Cannot be destroyed
'CMap':no appropriate default constructor available
Is any header has to include for this.
I am using vc++ 7.1 version?
Regards
Chezhian
|
|
|
|