|
I really need some advice with this „problem“.
I am rebuilding a class and according to the original its function is to act as „COM lookalike”Basically y a callback for DirectShow frame capture.
The original uses global variables and there is the “problem”.
No matter what I do the linker will complain about multiple definitions, but only on some variables.
I have made sure the variables are unique and compiled only once, same as the header file, but it does not help.
Here is the code:
#ifndef _CALLBACK_GLOBALS
#define _CALLBACK_GLOBALS
#pragma message( "Compiling " __FILE__ )
#pragma message( "Last modified on " __TIMESTAMP__ )
BOOL g_bOneShot_CB = FALSE;
DWORD g_dwGraphRegister_CB=0; // For running object table
HWND g_hwnd_CB;
// Structures
typedef struct _callbackinfo_CB
{
double dblSampleTime;
long lBufferSize;
BYTE *pBuffer;
BITMAPINFOHEADER bih;
}CALLBACKINFO_CB;
CALLBACKINFO_CB callback; // = {0};
#endif
And here is a small sample of linker errors:
_AVIFrame.obj : error LNK2005: "int g_bOneShot_CB" (?g_bOneShot_CB@@3HA) already defined in _Analysis_Contour.obj
_AVIFrame.obj : error LNK2005: "struct _callbackinfo_CB callback" (?callback@@3U_callbackinfo_CB@@A) already defined in _Analysis_Contour.obj
_Blob.obj : error LNK2005: "int g_bOneShot_CB" (?g_bOneShot_CB@@3HA) already defined in _Analysis_Contour.obj
_Blob.obj : error LNK2005: "struct _callbackinfo_CB callback" (?callback@@3U_callbackinfo_CB@@A) already defined in _Analysis_Contour.obj
_BlobTracker.obj : error LNK2005: "int g_bOneShot_CB" (?g_bOneShot_CB@@3HA) already defined in _Analysis_Contour.obj
_BlobTracker.obj : error LNK2005: "struct _callbackinfo_CB callback" (?callback@@3U_callbackinfo_CB@@A) already defined in _Analysis_Contour.obj
_ChildFrame_Tab.obj : error LNK2005: "int g_bOneShot_CB" (?g_bOneShot_CB@@3HA) already defined in _Analysis_Contour.obj
_ChildFrame_Tab.obj : error LNK2005: "struct _callbackinfo_CB callback" (?callback@@3U_callbackinfo_CB@@A) already defined in _Analysis_Contour.obj
_DocManager.obj : error LNK2005: "int g_bOneShot_CB" (?g_bOneShot_CB@@3HA) already defined in _Analysis_Contour.obj
_DocManager.obj : error LNK2005: "struct _callbackinfo_CB callback" (?callback@@3U_callbackinfo_CB@@A) already defined in _Analysis_Contour.obj
_DrawBitmap.obj : error LNK2005: "int g_bOneShot_CB" (?g_bOneShot_CB@@3HA) already defined in _Analysis_Contour.obj
And here is sample usage
STDMETHODIMP BufferCB( double dblSampleTime, BYTE * pBuffer, long lBufferSize )
{
if( !g_bOneShot_CB )
return 0;
// Since we can't access Windows API functions in this callback, just
// copy the bitmap data to a global structure for later reference.
callback.dblSampleTime = dblSampleTime;
callback.lBufferSize = lBufferSize;
PS I did change the BOOL to bool and the linker error now reads “bool g_bOneShot_CB”...
Any hint how to fix this would be appreciated.
Cheers
Vaclav
|
|
|
|
|
Declare the global variables in the .h file like:
extern BOOL g_bOneShot_CB;
extern DWORD g_dwGraphRegister;
and then in the corresponding .cpp file, define them like:
g_bOneShot_CB = FALSE;
g_dwGraphRegister_CB = 0;
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"You can easily judge the character of a man by how he treats those who can do nothing for him." - James D. Miles
|
|
|
|
|
Thanks David,
but I just found my stupid "problem". Or better yet, stupid found the problem!
THe orignal has two classes in one cpp file, I really do not understand why people do that - it just makes things convoluted and does not save anything.
I had the globals in my header file - mistake #1. After fixin that I had the header file in StdAfx and than BEFORE the globals - mistake #2 and #3.
Now both compiler and linker are OK.
Not the best solution, but now I can code!
Cheers
Vaclav
|
|
|
|
|
I use a CMapStringToString object to store some string key-value pairs, the string are read from a Unicode text file.
a.text like the following:
4001 English //space is a TAB key space
4002 German
4003 Chinese
4004 Russia
then I read the text file to a CString strLine, use
str1 = strLine.Tokenize(TEXT("\t"),tokenPos); to get token;
str2 = strLine.Tokenize(TEXT("\t"),tokenPos);
I set breakpoint, I can read the token is right,i.e. str1 = 4001/4002/4003/4004; str2 = English/German/Chinese/Russia every loop.
In the loop, I use :
mStrMap.SetAt(str1,str2);
and after loop;
mStrMap.Lookup(_T("4001"),tstStr);
mStrMap.Lookup(_T("4002"),tstStr);
mStrMap.Lookup(_T("4003"),tstStr);
mStrMap.Lookup(_T("4004"),tstStr);
The weird thing is , 4002/4003/4004 key, I got right value:
German/Chinese/Russia
but for 4001, I got an empty string;
I thought maybe it is oxFEFF (unicode BOM), so before the loop to readline circularly, I first read BOM so as to move the file pointer back.
But still, for 4001, I got an empty string.
Don't know why this happened.
modified 5-Mar-14 15:12pm.
|
|
|
|
|
You need to show the exact code. And please use <pre> tags around the code blocks so it is more readable thus:
mStrMap.Lookup(_T("4001"),tstStr);
mStrMap.Lookup(_T("4002"),tstStr);
mStrMap.Lookup(_T("4003"),tstStr);
mStrMap.Lookup(_T("4004"),tstStr);
You can automate that by selecting all the lines of code in the editor and using the code button at the top.
|
|
|
|
|
Sorry, it's my fault too. I read BOM, forgot to change the key string.
|
|
|
|
|
Please read the pseudo code as follows:
class A
{
CMap myMap;
A() {
myMap.InitHashTable(857);
}
};
void test(void)
{
A *pa = new A();
}
My question is, myMap member in A class is in Heap or Stack?
is destructor of A class need to delete myMap object expressly?
|
|
|
|
|
The actual memeory used by the Map is allocated internally and dynamically, so it will be on the Heap. You may need to delete the map in your destructor, it depends on the lifetime of your object.
|
|
|
|
|
So, the myMap memory allocation is dominated by it's container class A, right?
for pseudo code like the following:
void test() {
CMap myMap;
}
then I dont need to delete myMap expressly, right?myMap should be in function stack.
|
|
|
|
|
That is correct, as far as I recall; MFC classes clean up after themselves.
|
|
|
|
|
I try to use delete myMap, IDE shows cannot convert from 'CMap' to 'Void*'.
|
|
|
|
|
You need to show us your code, we cannot guess what you have done.
|
|
|
|
|
class A
{
private:
A m_Map;
public :
A();
~A();
};
A::A()
{
m_Map.InitHashTable(MAP_LEN);
}
A:~A()
{
delete m_ConfigMap;
}
error C2440: 'delete' : cannot convert from 'CMapStringToString' to 'void *'
|
|
|
|
|
I see two issues here:
1. Where is m_ConfigMap declared?
2. You have m_Map declared as an A . Is that what you meant?
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
sorry, yes, m_configMap should be m_Map.
|
|
|
|
|
That code makes no sense. You declare m_Map as an object of class A . You then try to call InitHashTable on it in the constructor, even though that function is not declared anywhere. Finally you try to delete m_ConfigMap which also is not declared anywhere.
|
|
|
|
|
I am using DirectShow "common" dshowutil.cpp file and I just found this, to me new , usage of #include directive.
It only works if included in a source file where its function(s) are used.
Makes sense.
Elsewhere the linker generates multiple definitions, so it must be included somewhere else, I did not search for it.
Here is the #include:
#pragma message("Common DirectShow support ")
#include "D:\00\0 SDK\DIrectShow 8.1 SDK\samples\Multimedia\DirectShow\Common\dshowutil.cpp"
And here is the usage sample:
TRACE("\nFind input and output pins and connect them");
IPin * pCapOut = GetOutPin( pDocument->pC_Graph->gcap.pVCap, 0 );
In my view it prepends the working source file.
I would like some other explanations from the group.
Is such usage of including cpp file common?
Thanks for your time.
CHeers
Vaclav
|
|
|
|
|
The #include statement is a preprocessor directive. The preprocessor is reading input files, processes his commands, and writes the result to an output file (source file name with extension 'i'). The #include statement just inserts the processed content of another file.
When invoking the compiler, the preprocessor is started first for each source file and the created preprocessed file is the input for the compiler. After compilation the file is deleted (the deletion can be omitted by passing a compiler option flag on the command line or setting it in the VS project setting).
It is not very common to include other source files but allowed.
|
|
|
|
|
Vaclav_Sal wrote: In my view it prepends the working source file But that is perfectly acceptable as long as all required include files are added within that cpp file. It is just the same as adding some extra functions at the top of a source file before the #include statements required by the remainder of the source.
|
|
|
|
|
So are the include cpp functions global only to the attched cpp which is basically an object / class?
Is that the reason I was getting multiple definitions when I included it in StdAfx header?
I did not try to access the preprocessed functions outside the class. It should not work.
Actually found that I was telling the DirectShow to add another filter and had no intermediate filter / pins to connect to. Fixed that so I do not need to do the connections manually.
|
|
|
|
|
Without seeing all the code in the included file it is impossible to answer that.
|
|
|
|
|
You are spot on Val you will get multiple inclusions if the file is multiple included, unless the file contains standard one time load #ifdef protection around the top and bottom
If the programmer knew what they were doing they would have something that looks like this top/bottom of include file
// PROTECTION TO STOP MULTIPLE UNIT LOADING
#ifndef _FILENAME_ID_
#define _FILENAME_ID_
#endif
It is still quite common in a very specific circumstance .. can you think what it might be
I will give you a hint:
I know the old version of windows.h from Microsoft did it but they changed it all a few years ago when they broke that unit up. You will probably also find it on the android source unless they worked there way around it.
|
|
|
|
|
I use a CmapStringToString object, put over 10000 key-value pairs into the object.
But I use:
test1 = mStrMap.GetCount();
test2 = mStrMap.GetHashTableSize();
try to get the map size.
test1 = 0x00000299
test2 = 0x00000011
I wonder what the meaning of GetCount(), and GetHashTableSize();
modified 5-Mar-14 11:12am.
|
|
|
|
|
With the following code
CMapStringToString mss;
for (int i=0; i<10000; ++i)
{
CString k,v;
k.Format("%05d", i);
v.Format("Foo%02d", i%100);
mss[k] = v;
}
int count = mss.GetCount();
int hsize = mss.GetHashTableSize();
I get:
count = 10000
hsize = 17
I don't know what exactly GetHashTableSize returns, the documentation is not much detailed about.
Veni, vidi, vici.
|
|
|
|
|
My fault, checked again, GetCount() works well for me too.
|
|
|
|