|
Thank you for the all answers.
But the question I made is not a beginner's question.
It is about exporting a static variable and if there is any reason why it is made so difficult to export it.
We know that it is possible to export a static member from a template class specialization,
We know that it is not possible to use the __declspec(dllexport) keyword with a template.
But in the example I gave I was able to get a static methods of a template exported even if the __declspec(dllexport) was not used. But this is not happening with a static data member.
The reason I am trying to do this is that I need to export and use a class created by using the Curiously Recurring Template Pattern (CRTP). In my case the template base class needs to have a static member.
About the third question, I am pretty sure that it is possible by using an export file (.def) and using a special keyword in it [ unfortunately I don't remember exactly how ].
Cheers,
Marcello
|
|
|
|
|
"Windows requires all public symbols to be explicitly exported from a DLL via the __declspec(dllexport) syntax (and correspondingly dllimported when referenced in some other DLL).
I guess it works pretty well on C libraries. But it doesn't work so well on C++ libraries, particularly with template classes--the template itself, of course, doesn't have a link-time presence, so it doesn't make sense to dllexport a template. What you really mean to export is the template instantatiation. But template instantiations are implicit, according to the language, so where do you put the dllexport syntax?
Microsoft came up with a place to put the dllexport syntax, which is to explicitly put a line like this in the DLL that exports a particular template instance:
Code:
template class __declspec(dllexport) my_template_class<my_instance>;
And also put a line like this in a DLL that imports that template instance:
Code:
extern template class __declspec(dllimport) my_template_class<my_instance>;
These lines must be the first instantiation of the template instance, which means they must be seen by the compiler before any other reference to my_template_class<my_instance>.
Of course, this is a Microsoft extension to C++ syntax; the language itself does not require this sort of declaration (and non-Microsoft compilers won't understand it).
The problem with this declaration is that it explicitly expands and exports all methods and components of the template class, whether they are actually used or not; and it requires that nested template classes be explicitly exported before their containing classes are exported.
That's not too bad, but it turns out that the standard STL implementation of list, map, set, multiset, multimap--basically everything other than vector--use nested template classes that are mutually recursive. That is, the nested class includes references to the containing class, and vice-versa. This makes it impossible to export the nested classes first, since expanding them requires expanding the containing class--which has not been exported yet, violating the rule that the export syntax must appear before the first instance is encountered. Similarly, you can't export the containing class first, which would expand the nested class before its export syntax. This means that none of the STL classes except for vector can be exported from a DLL.
But do you really need to export a template instance from a DLL? Isn't each instance of a template technically a completely new copy of the class? If you don't even try to export the class, you should end up with a new copy of the template code in each DLL, but since all of the copies are essentially the same, they should be compatible with each other. So what happens if you don't try to export the class?
It turns out this works, mostly, but the standard implementation of STL relies on some static members of the template class, which the language specifies that the linker should resolve to the same pointer value by runtime. The Microsoft DLL linker doesn't do this (because, without having explicitly exported the template classes, the linker sees them as unrelated classes). The net result is that any class that tries to expose iterators to its internal STL object, even via an inline method, will crash if those iterators are accessed by code in another DLL.
We spent a long time trying to figure out why our code, which worked fine on Unix, was crashing when we ported it to Windows. We finally tracked it down to this, and the only solution we could find--short of making everything non-inline and paying the corresponding run-time performance penalty--was to compile everything into one big DLL. Now, within the one DLL, all the iterators are valid and can be accessed by code in different modules.
This was back on VC6. Beginning with VC7.0, Microsoft started shipping with a third-party reimplementation of STL, that supposedly works around the DLL linker issue by not requiring static members to be unified. So presumably the issue is now a moot point on VC7.0 and above--you should be able to use STL iterators across DLL's now, although you still pay the cost of code bloat--although we haven't tested this."
/////////////////////////////////////////////////////////////////
// header file DLL
#ifdef MYDLL_EXPORTS<br />
#define MYDLL_API __declspec(dllexport)<br />
#else<br />
#define MYDLL_API __declspec(dllimport)<br />
#endif<br />
<br />
class MYDLL_API CMyDLL {<br />
public:<br />
CMyDLL(void);<br />
static void SetN(int x);<br />
static int GetN();<br />
static void show();<br />
static int n;<br />
};<br />
MYDLL_API int CMyDLL::n;
// CPP file DLL
CMyDLL::CMyDLL() { return; }<br />
<br />
void CMyDLL::show() {<br />
std::cout << "CMyDLL:show()" << std::endl;<br />
std::cout << n << std::endl;<br />
}<br />
<br />
void CMyDLL::SetN(int x) { n = x; }<br />
<br />
int CMyDLL::GetN() { return n; }
// main file
#include "stdafx.h"<br />
#include <iostream><br />
#include "myDLL.h"<br />
<br />
int main(int argc, char* argv[])<br />
{<br />
CMyDLL::n = 2;<br />
CMyDLL::SetN(9);<br />
int k1 = CMyDLL::n;<br />
std::cout << k1 << std::endl;<br />
CMyDLL::show();
return 0;<br />
}<br />
Result: // ???
2 // direct call n
CMyDLL:show()
9 // calling via function
|
|
|
|
|
Thank you so much for your answer, and for saving me a lot of time and trouble.
You really went to the core of problem I am having.
Unfortunately I worked for months to recode my program in separate DLL's in order to keep things separated.
I personally think that DLL are also a mean to keep things separated, so to unify all of them in a unique DLL is something I will do only if I have no other choice.
In my case I think I would rather find a way to eliminate the static member, even if it is really not a good solution because of the way my class is supposed to be used.
Only a question. Why in Unix you didn't meet this problem ? ( I know a bit about Linux, but not very much. )
Best Regards,
Marcello
|
|
|
|
|
I wanna know ways to make low-level operations to devices (mainly the hard disk) in .Net Framework by using C++ dll's or something ?????
By ways I mean maybe a class or a Windows standard API library (doesnt matter if its not managed code)
Specific things I want to know are (mostly consultations) :
- the beginning/ending number of cluster and track of files,
- the beginning/ending number of cluster and track of folders
- the size in clusters of files
- the volume serial number
- the size in clusters and tracks of a hard disk, etc
- can I do "interrupts" ???
Let me know the class or the Api library and the documentation, if there is it.
thanks in advance, fvalerin
|
|
|
|
|
It sounds like a device driver is in your future.
"Let us be thankful for the fools. But for them the rest of us could not succeed." - Mark Twain
"There is no death, only a change of worlds." - Native American Proverb
|
|
|
|
|
Well, no, I dont want to complicate my existence. I just want to read those kind of values
thanks, fvalerin
|
|
|
|
|
I know of no way to circumvent the HAL in order to get access to such low-level information.
For the fourth bullet, use GetVolumeInformation() .
"Let us be thankful for the fools. But for them the rest of us could not succeed." - Mark Twain
"There is no death, only a change of worlds." - Native American Proverb
|
|
|
|
|
I just saw this article:
Hooking the kernel directly
http://www.codeproject.com/useritems/soviet_direct_hooking.asp
maybe he can help you !
Marcello
|
|
|
|
|
Marcello wrote: maybe he can help you !
I'm not the one needing help, fvalerin was.
"Let us be thankful for the fools. But for them the rest of us could not succeed." - Mark Twain
"There is no death, only a change of worlds." - Native American Proverb
|
|
|
|
|
Yes, I meant fvalerin
|
|
|
|
|
is there any way to change the default color(blue) of title bar, and the color of text in a dialog application.
Thanks
|
|
|
|
|
i think only way is to draw them yourself on WM_NCPAINT message.
A special image tool for C++ programmers, don't miss it!
The world unique Software Label Maker is here for you and me ...
A nice hyper tool for optimizing your MS html-help contents.
|
|
|
|
|
|
Hello,
I have a weird error that I hope someone can help me with:
I have a program (SDI), whose view is derived from CPropertyView, a property sheet view by Leo Moll. When I run the application in debug mode, I have no problems whatsoever. However, if I change to release mode, I get the following:
depView.obj : error LNK2001: unresolved external symbol "protected: int __thiscall CDepView::OnCreate(struct tagCREATESTRUCTA *)" (?OnCreate@CDepView@@IAEHPAUtagCREATESTRUCTA@@@Z)
Release/dep.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.
dep.exe - 2 error(s), 0 warning(s)
In DepView.h, I have:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
In DepView.cpp, I have
BEGIN_MESSAGE_MAP(CDepView, CPropertyView)
ON_WM_CREATE()
...
END_MESSAGE_MAP()
and
int CDepView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
...
return 0;
}
If I remove either the declaration in the header file, or the implementation (and message map) in the source file, it compiles fine, but crashes when I close it (and of course doesnt initialize anything).
Does this sound familiar to anyone?
I have only seen this error when I forget to include the source file in the project, but I have checked that. What boggles my mind is that it works perfectly in debug mode.
Any help/comments would be greatly appreciated,
Thanks in advanced,
-----------------
Genaro
|
|
|
|
|
Just a guess: I'd check the preprocessor definitions for the release build and compare it to that of the debug build. In particular I'd pay attention to the UNICODE , _UNICODE and _MBCS defines.
Steve
|
|
|
|
|
Hi Stephen,
thanks for the reply. I checked the preprocessor settings, and as far as definitions are concerned, no difference, except for _debug vs. ndebug.
For project options,
Debug is:
/nologo /MDd /W3 /Gm /GX /ZI /Od /I
"C:\mysql++-1.7.1-win32-vc++\include"
/I
"C:\mysql++-1.7.1-win32-vc++\mysql\include"
/D "WIN32"
/D "_DEBUG"
/D "_WINDOWS"
/D "_AFXDLL"
/D "_MBCS"
/Fp"Debug/dep tool.pch"
/Yu"stdafx.h"
/Fo"Debug/"
/Fd"Debug/"
/FD /GZ /c
Release is:
/nologo /MD /W3 /GX /O2 /I
"C:\mysql++-1.7.1-win32-vc++\include"
/I
"C:\mysql++-1.7.1-win32-vc++\mysql\include"
/D "WIN32"
/D "NDEBUG"
/D "_WINDOWS"
/D "_AFXDLL"
/D "_MBCS"
/FR"Release/"
/Fp"Release/dep tool.pch"
/Yu"stdafx.h"
/Fo"Release/"
/Fd"Release/"
/FD /c
I can't find anything that would cause the error there... any clues?
-----------------
Genaro
|
|
|
|
|
Looks fine. I can't think of anymore suggestions. Good luck
Steve
|
|
|
|
|
I see at least five differences, which may or may not be the problem. Change the "Relase" values to match the "Debug" values and see if that makes a difference.
"Let us be thankful for the fools. But for them the rest of us could not succeed." - Mark Twain
"There is no death, only a change of worlds." - Native American Proverb
|
|
|
|
|
Thank you for you response,
I just figured it out a while ago. All I had to do was change the first line of the release options to match the debug options, and it worked.
Thanks a lot,
-----------------
Genaro
|
|
|
|
|
I have program that support only DLL, i want to send msg from it to MSMQ,
so what is the best things that i can do ? can i call function in DLL that have Code to send msg for MSMQ ? if not, then what to do ?
Ali
|
|
|
|
|
Hi
I am trying to understand when sender is useful.In what circumstances i need this?
I have a sample code :
<br />
void __fastcall TForm1::Button1Click(TObect *Sender) <br />
{ <br />
TButton *Button = dynamic_cast<TButton *>(Sender); <br />
if (Button) <br />
{ <br />
} <br />
else <br />
{ <br />
} <br />
} <br />
here it writes :
// do something when a call was made
// passing a NULL value for *Sender)
How can it possible?I mean what type of code passing NULL value for *Sender.I am confused.
Please help me to understand the functionality of sender.
Thanks.
|
|
|
|
|
The sender is a pointer to the object that raised the message ( so, it iwll be the button that was clicked ). I can't imagine why it would be called with NULL.
Christian Graus - Microsoft MVP - C++
|
|
|
|
|
I use bitmap on my dialog.
Also i use CtlColor function to create transparent static text.
The main problem is that my menu still has the same color.
How to create transparent menu for bitmap Dialog?
|
|
|
|
|
no such menu.
but u can draw or use some controls (i.e. static) to simulate "menu bar", when user clicks them, u popup sub-menu by TrackPopupMenu() function.
-- download last software in my signiture to see its performances.
A special image tool for C++ programmers, don't miss it!
The world unique Software Label Maker is here for you and me ...
A nice hyper tool for optimizing your MS html-help contents.
|
|
|
|
|
I have a little problem:
I use ado to connect to a mysql database (version 4.0.12) and mysql odbc driver(3.51).
The system works fine but recently i ran into this problem:
I've installed it on a LAN consisting of 5 win98SE stations making one of them the database server.
The program works on two of them quite ok but fails on the other 3. The thing is that the other 3 computers still connect to the db but some of the querys fail.
Actually is not the querys that fail but rather the call to _RecordsetPtr->GetCollect("field")
To be more precise a query like "SELECT id, name, address FROM clients" works.
A query like "SELECT clients.id AS id, clients.name AS name, ocupations.kind AS kind FROM clients AS clients, ocupations AS ocupations WHERE clients.ocupationid = ocupations.id" fails when i do a call to pRecordSet->GetCollect(L"kind") with invalid pointer.
Another thing to remember is that the database server is installed on one of the computers that do not work. The stations on which the program works connect to this computer via LAN
So, what do i do? Where should i search for the bug? I really have no ideea.
I never had this problem on winxp and this program works on several win88se networks
|
|
|
|
|