|
Appologies for the typo in the original post. Where __dllspec read <code>_declspec</code>.
However, I am not sure that I understand since the only thing I am building is two dlls (exes come much further down the line and they do not really know the variable).
Thus, how I create the g_iYourVariable initialise in one of source files of the first dll, use it in all other sources of the same dll, export it and be able to imported (assuming using __declspec(dllimport) ) in any other dll file)?
|
|
|
|
|
Thus, how I create the g_iYourVariable initialise in one of source files of the first dll, use it in all other sources of the same dll, export it and be able to imported (assuming using __declspec(dllimport)) in any other dll file)?
1 - define a handy macro to make it easy for your DLL to use dllexport and allow clients to use dllimport. Put it in a file, call it "MyDLLExports.h".
#ifdef BUILDING_MYDLL<br />
# define MyDLLExport __declspec(dllexport)<br />
#else<br />
# define MyDLLExport __declspec(dllimport)<br />
#endif
2 - compile all sources of your DLL with the preprocessor definition 'BUILDING_MYDLL' added - when building only your DLL.
3 - define a header file where your variable will exist. e.g.
#ifndef __MyDLL_MyVar_h__<br />
#define __MyDLL_MyVar_h__<br />
<br />
#include "MyDLLExports.h"<br />
<br />
MyDLLExport int MyDLLmyVar;<br />
<br />
#endif // __MyDLL_MyVar_h__
|
|
|
|
|
That's almost exactly how I did it. It seems to work but still get a linking warning of multiple definitions. I think the problem comes from the difference between the declaration and the definition with initialisation.
To be more specific my code originates from Unix. What I use to have there was
File export.h
<br />
#ifndef _my_variable_decl<br />
#define _my_variable_decl<br />
<br />
extern int my_var;<br />
<br />
#endif<br />
which was included by all the clients.
However, because the variable is external I have to redeclare it in a local file in one of my libraries. The declaration & its initialisation is
File globals.cpp
<br />
#include <export.h><br />
<br />
int my_var = 10;<br />
</export.h>
Now migrating to Win32 I transform it
File export.h
<br />
#ifndef _my_variable_decl<br />
#define _my_variable_decl<br />
<br />
#ifdef _WIN32<br />
#ifdef _MY_DLL <br />
#define MY_EXTERN __declspec(dllexport) extern<br />
#else <br />
#define MY_EXTERN __declspec(dllimport) extern<br />
#endif<br />
#else<br />
#define MY_EXTERN extern<br />
#endif<br />
<br />
MY_EXTERN int my_var;<br />
#endif<br />
and modified the initialisation as follows
File globals.cpp
<br />
#include <export.h><br />
<br />
#ifdef _WIN32<br />
#define MY_GLOBAL _declspec(dllexport)<br />
#else<br />
#define MY_GLOBAL <br />
#endif<br />
<br />
MY_GLOBAL int my_var = 10;<br />
</export.h>
As you said the _MY_DLL is set only when I compile the main dll part of it is globals.cpp. Other dlls include export.h. This code works and my_var behaves as a global variable inside the main dll and any other dll (note also that it is still compatible with UNIX). However, when I build the main DLL I get a warning of
globals.obj : warning LNK4197: export "?my_var@@3IA" specified multiple times; using first specification which is due to the fact that _WIN32 think that the variable is declared twice (at least that's what my Visual C++ 6.0 compiler says).
I tried to remove the extern keyword in the windows part of the export.h but then it does not compile. I tried to add a __declspec(selectany) and again I get the same warning.
It is an annoying warning and nothing more so I am incline to endure it since my_var is a real global variable.
I thought to reshape the code as following
File export.h
<br />
#ifndef _my_variable_decl<br />
#define _my_variable_decl<br />
<br />
#ifdef _WIN32<br />
#ifdef _MY_DLL <br />
#define MY_EXTERN(_type, _var, _val) __declspec(dllexport) _type _var = _val<br />
#else <br />
#define MY_EXTERN(_type, _var, _val) __declspec(dllimport) _type _var<br />
#endif<br />
#else<br />
#define MY_EXTERN extern _type _var<br />
#endif<br />
<br />
MY_EXTERN(int, my_var, 10); <br />
<br />
#endif<br />
File globals.cpp
<br />
#include <export.h><br />
<br />
#ifdef _WIN32<br />
#define MY_GLOBAL(_type, _var, _val)<br />
#else<br />
#define MY_GLOBAL(_type, _var, _val) _type _var = val<br />
<br />
#endif<br />
<br />
MY_GLOBAL(int, my_var, 10);<br />
</export.h>
but by doing that I am not sure how many instance of my_var do I have. Would be one or more than one as my export.h will be include by more than one sources in the main dll? Also it introduces the danger that the initial value is specified in two different places (one for Unix and one for Win32) and this may lead to bugs in future (forget to update one of the two).
modified on Thursday, April 10, 2008 9:33 AM
|
|
|
|
|
There may be a easier way to do this, but one way is to create global shared memory is to use CreateFileMapping on one DLL, and OpenFileMapping in the other.
Pseudo-code is something like:
DLL #1
------
int *pMemory;
hMem = CreateFileMapping(....."MySharedMemory");
pMemory = (int *)MapViewOfFile(hMem);
pMemory = 3;
DLL #2
-------
int *pMemory;
int Value;
hMem = OpenFileMapping(....."MySharedMemory");
pMemory = (int *)MapViewOfFile(hMem);
Value = *pMemory;
Note sure if this is 100% correct, its been a while since I used it. grep in codeproject for "Shared Memory with IPC with threads" to get more details.
|
|
|
|
|
Thanks but I think shared memory will complicate my code immencelly. I gave it a thought but then it is too much of a complication. In the worse case I 'll keep it as it is and will have to ignore the compiler warnings. After all despite the warnings the existing code seems to work (not sure though if it is by accident though).
|
|
|
|
|
Hello everyone,
In the book ATL Internals, it is mentioned, the properties of CComPtr is,
--------------------
Release the encapsulated interface pointer when the class destructor executes;
Automatically releases its interface pointer during exception handling, ...
--------------------
They both means invoking the Relase method (inherited from IUnknown) of the interface?
thanks in advance,
George
|
|
|
|
|
|
Thanks led mike,
Question answered.
regards,
George
|
|
|
|
|
Hello everyone,
1.
BSTR is always wide character buffer. I do not know why the name of the macro A2WBSTR is so special and add a needless 'W'?
For others dealing with BSTR, since it is already wide character buffer, 'W' is no need. Like W2BSTR, and A2WSTR.
2.
What is differences between A2WBSTR and A2BSTR? Can not find answer from search.
thanks in advance,
George
|
|
|
|
|
Yes, AFAIK, BSTR s were (and are) always wide-character strings.
Perhaps the reason they did this was to specify the encoding of the characters in the BSTR ? Likely not, but just a guess.
Of course, you could always just look at how those macros/functions are implemented to try and find differences!
Peace!
-=- James Please rate this message - let me know if I helped or not!<hr></hr> If you think it costs a lot to do it right, just wait until you find out how much it costs to do it wrong! Remember that Professional Driver on Closed Course does not mean your Dumb Ass on a Public Road! See DeleteFXPFiles
|
|
|
|
|
|
On my system, provided _ATL_EX_CONVERSION_MACROS_ONLY symbol is not defined, they are the same
#if defined(_UNICODE)
inline BSTR T2BSTR_EX(__in_opt LPCTSTR lp) {return ::SysAllocString(lp);}
inline BSTR A2BSTR_EX(__in_opt LPCSTR lp) {return A2WBSTR(lp);}
inline BSTR W2BSTR_EX(__in_opt LPCWSTR lp) {return ::SysAllocString(lp);}
#ifndef _ATL_EX_CONVERSION_MACROS_ONLY
inline BSTR T2BSTR(__in_opt LPCTSTR lp) {return ::SysAllocString(lp);}
inline BSTR A2BSTR(__in_opt LPCSTR lp) {return A2WBSTR(lp);}
inline BSTR W2BSTR(__in_opt LPCWSTR lp) {return ::SysAllocString(lp);}
#endif // _ATL_EX_CONVERSION_MACROS_ONLY
#else // !defined(_UNICODE)
inline BSTR T2BSTR_EX(__in_opt LPCTSTR lp) {return A2WBSTR(lp);}
inline BSTR A2BSTR_EX(__in_opt LPCSTR lp) {return A2WBSTR(lp);}
inline BSTR W2BSTR_EX(__in_opt LPCWSTR lp) {return ::SysAllocString(lp);}
#ifndef _ATL_EX_CONVERSION_MACROS_ONLY
inline BSTR T2BSTR(__in_opt LPCTSTR lp) {return A2WBSTR(lp);}
inline BSTR A2BSTR(__in_opt LPCSTR lp) {return A2WBSTR(lp);}
inline BSTR W2BSTR(__in_opt LPCWSTR lp) {return ::SysAllocString(lp);}
#endif // _ATL_EX_CONVERSION_MACROS_ONLY
#endif // defined(_UNICODE)
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
|
|
|
|
|
Hi CPallini,
After checking implementation in my system (MSVC 2008), my conclusion,
A2BSTR is for null terminated string input, and A2WBSTR can be non-null terminated and assign an additional length field.
Correct?
_Check_return_ inline BSTR A2WBSTR(_In_opt_ LPCSTR lp, int nLen = -1)
{
if (lp == NULL || nLen == 0)
return NULL;
USES_CONVERSION_EX;
BSTR str = NULL;
#pragma warning(push)
#pragma warning(disable: 6385)
int nConvertedLen = MultiByteToWideChar(_acp_ex, 0, lp,
nLen, NULL, NULL);
#pragma warning(pop)
int nAllocLen = nConvertedLen;
if (nLen == -1)
nAllocLen -= 1;
str = ::SysAllocStringLen(NULL, nAllocLen);
if (str != NULL)
{
int nResult;
nResult = MultiByteToWideChar(_acp_ex, 0, lp, nLen, str, nConvertedLen);
ATLASSERT(nResult == nConvertedLen);
if(nResult != nConvertedLen)
{
SysFreeString(str);
return NULL;
}
}
return str;
}
regards,
George
|
|
|
|
|
I don't know, because you did not post the A2BSTR definition (in your MSSVC 2008).
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
|
|
|
|
|
Here it is, CPallini.
Do you think my previous analysis is correct?
inline BSTR A2BSTR(_In_opt_ LPCSTR lp) {return A2WBSTR(lp);}
regards,
George
|
|
|
|
|
You analysis is wrong.
A2BSTR do no more and no less then calling A2WBSTR , i.e. their effect is identical (there is even no difference in involved stack levels, since A2BSTR it is declared inline).
BTW all BSTR must have a length field (this is the reason why you typically call SysAllocString to alloc a BSTR rather than doing it directly).
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
|
|
|
|
|
Thanks CPallini,
CPallini wrote: A2BSTR do no more and no less then calling A2WBSTR, i.e. their effect is identical
I do not agree with you. I think for A2WBSTR you can specify the 2nd argument, which is the length of the ANSI string input, but for A2BSTR, you can not, you can only use the implicit default parameter -1.
Agree? Any comments?
regards,
George
|
|
|
|
|
You're right (and I'm blind ).
A2WBSTR seems more flexible: you may convert only a chunk of the original ANSI string.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
|
|
|
|
|
Thanks CPallini,
Question answered.
regards,
George
|
|
|
|
|
I came across this use of the "new" keyword in a library recently. I had to look it up to see what was going on. Apparently its valid, I've just never seen it before in any code examples, books, articles, etc.
If you write a custom new operator, you can write it to take an extra argument. When callers use the new keyword they supply an additional argument which gets passed to the new operator.
So you can call
MyClass* instance = new 128 MyClass;
This creates an instance of MyClass as expected but when invoking the custom new operator passes along the argument 128.
Anyway, I'm just curious if anyone else has seen or used this. It caught me off guard.
|
|
|
|
|
Have not seen it done like that before, but I could see it being used for things like allocating additional memory at the end of the object. Remember how variable-length structures like DDEDATA , PDH_COUNTER_INFO and some device driver ones worked?
Also for custom heap management - I want this object on this heap and that object created on on that heap, or created in a pre-reserved (shared?) block of memory.
Peace!
-=- James Please rate this message - let me know if I helped or not!<hr></hr> If you think it costs a lot to do it right, just wait until you find out how much it costs to do it wrong! Remember that Professional Driver on Closed Course does not mean your Dumb Ass on a Public Road! See DeleteFXPFiles
|
|
|
|
|
Dave Calkins wrote: Anyway, I'm just curious if anyone else has seen or used this. It caught me off guard.
Placement new, perhaps?
"Love people and use things, not love things and use people." - Unknown
"To have a respect for ourselves guides our morals; to have deference for others governs our manners." - Laurence Sterne
|
|
|
|
|
Placement new required the use of parenthesis:
new (value) Type Although now that I think about it, you may be correct. I think that placement new is the only way to pass parameters to new ...?
Peace!
-=- James Please rate this message - let me know if I helped or not!<hr></hr> If you think it costs a lot to do it right, just wait until you find out how much it costs to do it wrong! Remember that Professional Driver on Closed Course does not mean your Dumb Ass on a Public Road! See DeleteFXPFiles
|
|
|
|
|
James R. Twine wrote: I think that placement new is the only way to pass parameters to new...?
AFAIK, you can override the new operator. I think that's what is done for the MFC: the file and line are passed to the new operator in order to track memory leaks easier.
|
|
|
|
|
Yep - yer right...
-=- James Please rate this message - let me know if I helped or not!<hr></hr> If you think it costs a lot to do it right, just wait until you find out how much it costs to do it wrong! Remember that Professional Driver on Closed Course does not mean your Dumb Ass on a Public Road! See DeleteFXPFiles
|
|
|
|
|