I’m developing a small OOP/RAII library that wraps Win32’s mixerXXX API functions.
I’m writing a class that encapsulates the MIXERLINE structure, so my MixerLine class has this as its header:
#pragma once
#define UNICODE
#include <stdio.h>
#include <string>
#include <windows.h>
#include "MixerDevice.h"
//////////////////////////////
class MixerLine {
private:
MIXERLINE _mixerLine;
public:
MixerLine(MixerDevice& parentMixer, DWORD destinationIndex);
~MixerLine();
};
However I get a syntax error (in VC9):
Error 2 error C2061: syntax error : identifier ‘MixerDevice’ d:\tfs\misc\winwavein\mixerline.h
Why isn’t the message more helpful? I have no idea what’s wrong with it.
FWIW, there are no errors at all in the file MixerDevice.h.
EDIT: Here are the original, entire files:
MixerLine.h
#pragma once
#define UNICODE
#include <stdio.h>
#include <string>
#include <windows.h>
#include "MixerDevice.h"
//////////////////////////////
class MixerLine {
private:
MIXERLINE _mixerLine;
public:
MixerLine(MixerDevice& parentMixer, DWORD destinationIndex);
~MixerLine();
// Properties
DWORD getDestinationLineIndex() {
return _mixerLine.dwDestination;
}
DWORD getSourceIndex() {
return _mixerLine.dwSource;
}
DWORD getLineId() {
return _mixerLine.dwLineID;
}
DWORD getStatus() {
return _mixerLine.fdwLine;
}
std:wstring getStatusString() {
switch( _mixerLine.fdwLine ) {
case MIXERLINE_LINEF_ACTIVE:
return L"MIXERLINE_LINEF_ACTIVE";
case MIXERLINE_LINEF_DISCONNECTED:
return L"MIXERLINE_LINEF_DISCONNECTED";
case MIXERLINE_LINEF_SOURCE:
return L"MIXERLINE_LINEF_SOURCE";
default:
return L"";
}
}
DWORD getUserData() {
return _mixerLine.dwUser;
}
DWORD getComponentType() {
return _mixerLine.dwComponentType;
}
};
MixerDevice.h
#pragma once
#define UNICODE
#include <memory>
#include <stdio.h>
#include <iostream>
#include <vector>
#include <windows.h>
////////////////////////
#include "MixerLine.h"
class MixerDevice {
private:
DWORD _deviceId;
HMIXER _mixerHandle;
MIXERCAPS _mixerCaps;
public:
MixerDevice(DWORD deviceId);
~MixerDevice();
void enumerateLines();
// Properties
DWORD getDeviceId() {
return _deviceId;
}
HMIXEROBJ getHandle() {
return (HMIXEROBJ)_mixerHandle;
}
// Caps
WORD getManufacturerId() {
return _mixerCaps.wMid;
}
WORD getProductId() {
return _mixerCaps.wPid;
}
MMVERSION getDriverVersion() {
return _mixerCaps.vDriverVersion;
}
WCHAR* getProductName() {
return _mixerCaps.szPname;
}
DWORD getSupportBits() {
return _mixerCaps.fdwSupport;
}
DWORD getDestinationCount() {
return _mixerCaps.cDestinations;
}
};
MixerDevice.cpp (the file I’m trying to compile):
#include "MixerDevice.h"
using namespace std;
MixerDevice::MixerDevice(DWORD deviceId) {
_deviceId = deviceId;
MMRESULT result;
result = mixerOpen( &_mixerHandle, deviceId, NULL, NULL, MIXER_OBJECTF_MIXER );
if( result != MMSYSERR_NOERROR ) throw new exception("Call to mixerOpen failed.", result);
result = mixerGetDevCaps( (UINT)_mixerHandle, &_mixerCaps, sizeof(MIXERCAPS) );
if( result != MMSYSERR_NOERROR ) throw new exception("Call to mixerGetDevCaps failed.", result);
}
MixerDevice::~MixerDevice() {
MMRESULT result = mixerClose( _mixerHandle );
if( result != MMSYSERR_NOERROR ) exit(666);
}
// Methods
void MixerDevice::enumerateLines() {
}
As Luchian Grigore already stated, a forward-declaration is better if it’s sufficient than including the whole header (at least, here, and IMHO).
#pragma oncedoes not help with circular inclusions, it only avoids infinite inclusions._But the inclusion starts within
MixerDevice.cpp:MixerDevice.cpp —
#include–> MixerDevice.h —#include–> MixerLine.h —#include–>MixerDevice.hThat last
#includedirective does nothing because of the#pragma onceinMixerDevice.h. The preprocessor assembles a single document (translation unit) that looks like (use/Por/showIncludesto see that):This is what the compiler receives as input, effectively. Now, when the compiler reaches the line within the contents of
MixerLine.h:The name
MixerDeviceis not known yet; that name is introduced “below” in the document within the contents ofMixerDevice.h. You need at least declare the classMixerDevicebefore using its name. You could also change your inclusion order asMixerDevicecurrently does not depend onMixerLine, but you’ll probably run into more trouble later this way.After some discussion with Luchian Grigore I want to point out:
Don’t solve the problem by reversing the inclusion order, this solution is something that works ONLY in this particular case and ONLY if you mention no name in
MixerDevice.hthat is only declared inMixerLine.h. Use forward-declarations instead, as mentioned by Luchian Grigore.