I'm having a bit of trouble retrieving the name of a monitor with winapi. According to other entries on stackoverflow, the correct way to get the name of a monitor is this:
EnumDisplayDevices(nullptr, 0, &oDisplayDevice, 0);
char lpszDeviceName[32];
memcpy(lpszDeviceName, oDisplayDevice.DeviceName, 32);
EnumDisplayDevices(lpszDeviceName, 0, &oDisplayDevice, 0);
char lpszMonitorName[128];
memcpy(lpszMonitorName, oDisplayDevice.DeviceString, 128);
However, EnumDisplayDevices returns FALSE the second time around. The first time around, DeviceName is \\DISPLAY1 and DeviceString is the GPU vendor. Using the MONITORINFOEX struct gives me the same value as DeviceName.
To be clear I'm looking for something like "Samsung blah blah," or what appears in the control panel on the screen resolution page.
This seems to return the proper data for me:
#include <Windows.h>
#include <iostream>
#include <string>
int main()
{
DISPLAY_DEVICE dd;
dd.cb = sizeof(dd);
int deviceIndex = 0;
while(EnumDisplayDevices(0, deviceIndex, &dd, 0))
{
std::string deviceName = dd.DeviceName;
int monitorIndex = 0;
while(EnumDisplayDevices(deviceName.c_str(), monitorIndex, &dd, 0))
{
std::cout << dd.DeviceName << ", " << dd.DeviceString << "\n";
++monitorIndex;
}
++deviceIndex;
}
return 0;
}
If you're compiling for UNICODE then use this instead:
#include <Windows.h>
#include <iostream>
#include <string>
int main()
{
DISPLAY_DEVICE dd;
dd.cb = sizeof(dd);
int deviceIndex = 0;
while(EnumDisplayDevices(0, deviceIndex, &dd, 0))
{
std::wstring deviceName = dd.DeviceName;
int monitorIndex = 0;
while(EnumDisplayDevices(deviceName.c_str(), monitorIndex, &dd, 0))
{
std::wcout << dd.DeviceName << L", " << dd.DeviceString << L"\n";
++monitorIndex;
}
++deviceIndex;
}
return 0;
}
Here's an example of the output:
\.\DISPLAY1\Monitor0, Dell U2410(DP)\.\DISPLAY2\Monitor0, Dell
2407WFP-HC (Digital)
This worked for me on Win10. "Retired Ninja" answer returned Generic PnP monitor.
Don't forget to add DEFINES += "WINVER=0x0601" or define that
#include <windows.h>
void QueryDisplay()
{
std::vector<DISPLAYCONFIG_PATH_INFO> paths;
std::vector<DISPLAYCONFIG_MODE_INFO> modes;
UINT32 flags = QDC_ONLY_ACTIVE_PATHS;
LONG isError = ERROR_INSUFFICIENT_BUFFER;
UINT32 pathCount, modeCount;
isError = GetDisplayConfigBufferSizes(flags, &pathCount, &modeCount);
if( isError )
{
return;
}
// Allocate the path and mode arrays
paths.resize(pathCount);
modes.resize(modeCount);
// Get all active paths and their modes
isError = QueryDisplayConfig(flags, &pathCount, paths.data(), &modeCount, modes.data(), nullptr);
// The function may have returned fewer paths/modes than estimated
paths.resize(pathCount);
modes.resize(modeCount);
if ( isError )
{
return;
}
// For each active path
int len = paths.size();
for( int i=0 ; i<len ; i++ )
{
// Find the target (monitor) friendly name
DISPLAYCONFIG_TARGET_DEVICE_NAME targetName = {};
targetName.header.adapterId = paths[i].targetInfo.adapterId;
targetName.header.id = paths[i].targetInfo.id;
targetName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
targetName.header.size = sizeof(targetName);
isError = DisplayConfigGetDeviceInfo(&targetName.header);
if( isError )
{
return;
}
QString mon_name = "Unknown";
if( targetName.flags.friendlyNameFromEdid )
{
mon_name = QString::fromStdWString(
targetName.monitorFriendlyDeviceName);
}
qDebug() << "Monitor " << mon_name;
}
}
Related
example picture
Im trying to constantly update the console number related to altitude. At the moment its a static number, and does not update while the plane is gaining, or loosing altitude. There is a comment near the bottom of the text referring to the prinf() that im using to send it to console(not sure what all was needed to be seen so I sent it all).
#include <iostream>
#include <Windows.h>
#include "SimConnect.h"
#include <string>
#include <sstream>
using namespace std;
HANDLE hSimConnect = NULL;
enum DATA_DEFINE_ID
{
DEFINITION_ID_AP,
};
enum DATA_REQUEST_ID
{
REQUEST_AP_SETTINGS,
};
enum EVENT_ID
{
EVENT_SET_AP_ALTITUDE,
};
struct DataRefs
{
double altitude;
double knots;
};
int main() {
HRESULT hr;
SIMCONNECT_RECV* pData = NULL;
DWORD cbData = 0;
bool bRequestProcessed = false;
int SelectedAltitude = 0;
SIMCONNECT_RECV_SIMOBJECT_DATA* pObjData = NULL;
DataRefs* pDataRefs = NULL;
if (SUCCEEDED(SimConnect_Open(&hSimConnect, "Client Event", NULL, NULL, NULL, NULL))) {
printf("Connected to MSFS2020!\n");
}
else {
/* string str = "42";
int num2 = stoi(str);
cout << num2;
*/
printf("Failed to Connect to MSFS2020\n");
}
//simVars
hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_ID_AP, "PLANE ALTITUDE", "Feet");
//hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_ID_AP, "AIRSPEED TRUE", "Knots");
// Check simVars
hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_AP_SETTINGS, DEFINITION_ID_AP, SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD_ONCE);
if (FAILED(hr))
{
printf("RequestDataOnSimObject for AutopilotData structure - error\n");
}
bRequestProcessed = false;
while (!bRequestProcessed)
{
hr = SimConnect_GetNextDispatch(hSimConnect, &pData, &cbData);
if (SUCCEEDED(hr))
{
pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA*)pData;
pDataRefs = (DataRefs*)&pObjData->dwData;
/* int altint;
altint = stoi (pDataRefs->altitude);
string str = "42";
int num2 = stoi(str);
cout << num2;
*/
/*
printf("\rCurrent plane altitude: %.f feet", pDataRefs->altitude);
fflush(stdout);
*/
//This line of code is what im referring to
printf("\rCurrent altitude: %.f feet", pDataRefs->altitude);
//printf("\rCurrent speed: %.f knots", pDataRefs->knots);
}
}
// Close
hr = SimConnect_Close(hSimConnect);
return 0;
}
Found the issue. If you CTRL-F "hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_AP_SETTINGS, DEFINITION_ID_AP, SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD_ONCE);", you can see that I use SIMCONNECT_PERIOD_ONCE. looking into the documentation (https://www.prepar3d.com/SDKv4/sdk/simconnect_api/references/structures_and_enumerations.html), I replaced SIMCONNECT_PERIOD_ONCE with SIMCONNECT_PERIOD_SECOND to update it every second.
I am trying to detect how many instances of a application person is running. Did he open my application once? Twice? Thrice?
I tried to detect it by checking it's instances by process names, but in windows it is pointles - people might change .exe name and it won't count towards final number.
How would I proceed then? I thought about searching it by className (HWND?) rather by processName, but how would I do it?
This is the code I am using for detecting by process name:
int Platform::getMulticlientCount(const std::string& ProcessName)
{
PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) };
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
const char *cstr = ProcessName.c_str();
int counter = 0;
if (Process32First(hSnapshot, &pe32))
{
do
{
if (_tcsicmp(pe32.szExeFile, cstr) == 0)
{
counter++;
}
} while (Process32Next(hSnapshot, &pe32));
}
CloseHandle(hSnapshot);
return counter;
}
The instance of the Remy:
static int counter;
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
char classname[MAX_PATH] = { 0 };
GetClassNameA(hwnd,classname, MAX_PATH);
if (_tcsicmp(classname, (char*)lParam) == 0)
counter++;
return true;
}
int Platform::getMulticlientCount(const std::string& ClassName)
{
counter = 0;
const char *cstr = ClassName.c_str();
EnumWindows(EnumWindowsProc, (LPARAM)cstr);
return counter;
}
If you also need to get the instance, in EnumWindowsProc:
HINSTANCE instance = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
If you also need to get the processId, in EnumWindowsProc:
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
Here is an example code that counts the instances that are running. While the application count the instances it self it does not matter if the binary is renamed. I used a file to keep the example simple but registry would work too. The only thing that is missing is a global mutex to protect the file against concurrent access. HTH
#include <iostream>
#include <thread>
#include <fstream>
#include <Windows.h>
class GlobalCounter
{
public:
GlobalCounter(const std::string& id)
: _id(id)
{
const auto filename = "C:\\users\\twollgam\\" + id + ".counter";
if (GlobalFindAtomA(id.c_str()) == 0)
{
std::ofstream(filename) << 1;
std::cout << "I am the first instance." << std::endl;
}
else
{
auto counter = 0;
std::ifstream(filename) >> counter;
++counter;
std::ofstream(filename) << counter;
std::cout << "I am the " << counter << " instance." << std::endl;
}
_atom = GlobalAddAtomA(id.c_str());
}
~GlobalCounter()
{
const auto filename = "C:\\users\\twollgam\\" + _id + ".counter";
auto counter = 0;
std::ifstream(filename) >> counter;
--counter;
std::ofstream(filename) << counter;
GlobalDeleteAtom(_atom);
}
private:
const std::string _id;
ATOM _atom;
};
int main()
{
const auto globalCounter = GlobalCounter("test");
std::cout << "Hello World!\n";
std::this_thread::sleep_for(std::chrono::seconds(30));
return 0;
}
If I plug in a device, say /dev/ttyUSB0 and I want to get the number 0 based on its VID:PID (found with lsusb), how could I do that in C++ Linux? I have this code to find one printer device, if it's helpful at all:
int printer_open (void)
{
char printer_location[] = "/dev/usb/lpX";
struct stat buf;
// continuously try all numbers until stat returns true for the connected printer
for (int i = 0; i < 10; i++)
{
printer_location[11] = '0' + i;
if (!stat (printer_location, &buf))
break;
}
return 0;
}
You could use libusb
apt-get install build-essential libudev-dev
Here is a good example: http://www.dreamincode.net/forums/topic/148707-introduction-to-using-libusb-10/
and here is the lib description: http://libusb.sourceforge.net/api-1.0/
int main() {
libusb_context *context = NULL;
libusb_device **list = NULL;
int rc = 0;
ssize_t count = 0;
rc = libusb_init(&context);
assert(rc == 0);
count = libusb_get_device_list(context, &list);
assert(count > 0);
for (size_t idx = 0; idx < count; ++idx) {
libusb_device *device = list[idx];
libusb_device_descriptor desc = {0};
rc = libusb_get_device_descriptor(device, &desc);
assert(rc == 0);
printf("Vendor:Device = %04x:%04x\n", desc.idVendor, desc.idProduct);
}
}
And if you compile your code don't forget to add the lib reference -I/usr/include/libusb-1.0/ and - lusb-1.0
libusb can't get it actually. So look at this file instead: /proc/bus/input/devices
Example line from the file:
I: Bus=0003 Vendor=1a2c Product=0c23 Version=0110
N: Name="USB USB Keyboard"
P: Phys=usb-0000:00:14.0-3/input0
S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0/0003:1A2C:0C23.0015/input/input30
U: Uniq=
H: Handlers=sysrq kbd event10 leds
B: PROP=0
B: EV=120013
B: KEY=1000000000007 ff800000000007ff febeffdff3cfffff fffffffffffffffe
B: MSC=10
B: LED=7
This function gets the event number from the device with the matching VID:PID:
#include <string>
#include <iostream>
#include <fstream>
void open_device (std::string device_vid, std::string device_pid)
{
try
{
std::ifstream file_input;
std::size_t pos;
std::string device_path, current_line, search_str, event_str;
std::string device_list_file = "/proc/bus/input/devices";
bool vid_pid_found = false;
int fd = 0;
bool debug = true;
// 1. open device list file
file_input.open(device_list_file.c_str());
if (!file_input.is_open())
{
std::cerr << "file_input.open >> " << std::strerror(errno) << std::endl;
throw -2;
}
// 2. search for first VID:PID and get event number
search_str = "Vendor=" + device_vid + " Product=" + device_pid;
while (getline(file_input, current_line))
{
if (!vid_pid_found)
{
pos = current_line.find(search_str, 0);
if (pos != std::string::npos)
{
vid_pid_found = true;
search_str = "event";
}
}
else
{
pos = current_line.find(search_str, 0);
if (pos != std::string::npos)
{
event_str = current_line.substr(pos);
// find space and substring event##
pos = event_str.find(' ', 0);
event_str = event_str.substr(0, pos);
break;
}
}
}
// 3. build device path
device_path = "/dev/input/" + event_str;
if (debug) std::cout << "device_path = " << device_path << std::endl;
// 4. connect to device
fd = open (device_path.c_str(), O_RDONLY);
if (fd < 0)
{
std::cerr << "open >> errno = " << std::strerror(errno) << std::endl;
throw -3;
}
}
catch (const std::exception &e)
{
std::cerr << "e.what() = " << e.what() << std::endl;
throw -1;
}
return;
}
I have a 3rd party .dll (and relative .h and .lib) to control a device via USB.
I want to use the dll functions into a class (AOTF_controller) to implement my desired behaviour.
What I want to do is :
Connect to the device (connect() class function);
Initialize it (init() class function);
Set some parameters (setScanningFreq() class function)
Increase sequentially the frequency of my device (increaseFreq() class function)
Reset and close the USB connection.
I can obtain this behavior when I use the dll functions directly into the _tmain() therefore the device works correctly, but when I wrap the dll functions into a class and try to use the class something goes wrong.
I repeat the above process (list item 1-5) several times: sometimes it works fine, sometimes the program stop and the debugger gives me this error:
First-chance exception at 0x77533fb7 in AOTFcontrollerDebug.exe: 0xC0150014: The activation context activation stack for the running thread of execution is corrupt.
The error seems random, sometimes I can conclude 80 times the scan without any problem, sometimes it gives me error right at the first scan.
I tried to search for that error but I was not able to find anything useful.
Anyone can help? I guess could be related on how the dll functions are called in my class?
Here is the main function code:
// AOTFcontrollerDebug.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "AOTFcontrollerDebug.h"
#include "AOTF_Controller.h"
#include <iostream>
#include <string>
#include <sstream>
#include <AotfLibrary.h>
#define DEFAULT_STARTFREQUENCY 78
#define DEFAULT_ENDFREQUENCY 95.5
#define DEFAULT_NUMOFFRAMES 256
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// The one and only application object
CWinApp theApp;
using namespace std;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(NULL);
if (hModule != NULL)
{
// initialize MFC and print and error on failure
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
// TODO: code your application's behavior here.
std::cout << "-----AOTF Controller Debugging-----"<<endl;
//input of scans to do
int repeatedScan;
std::cout << "Type how many repeated scan: "<<endl;
std::cin >> repeatedScan;
//instance
AOTF_Controller m_AOTF_Controller;
std::cout << "AOTF Controller instance done..."<<endl;
//loop over scans
for(int i =0;i<repeatedScan;i++)
{
m_AOTF_Controller.connect();
std::cout << "AOTF Controller connected..."<<endl;
std::cout << "Scan number : "<< (i + 1) <<endl;
m_AOTF_Controller.init();
//set the delta freq to increase at each step
m_AOTF_Controller.setScanningFreq(DEFAULT_STARTFREQUENCY, DEFAULT_ENDFREQUENCY, DEFAULT_NUMOFFRAMES);
//loop over wavelengths
int sleep_ms = 4;
for (int j =0; j <DEFAULT_NUMOFFRAMES; j++)
{
Sleep(sleep_ms) ;
m_AOTF_Controller.increaseFreq();
//std::cout << " "<< (j + 1) ;
}
// terminate scans
m_AOTF_Controller.reset();
m_AOTF_Controller.disconnect();
std::cout << endl <<"Scan number "<< (i + 1) << "terminated successfully" <<endl;
Sleep(sleep_ms*100) ;
}
}
}
else
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: GetModuleHandle failed\n"));
nRetCode = 1;
}
return nRetCode;
}
and here the Aotf_Controller class code:
//Aotf_Controller.h
#pragma once
#include <AotfLibrary.h>
#include <string>
#include <sstream>
#include <iomanip>
#define CONVERSION_MHZ_TO_HZ 1000000
class AOTF_Controller
{
private:
enum Error {SUCCESSFUL , CONNECTION_ERROR, DISCONNECTION_ERROR, INIT_ERROR, RESET_ERROR , SET_ERROR }; // error enum values
HANDLE hAotfController;
int currentGain;
long currentFreq; // current frequency in Hz
long startFreq, endFreq, deltaFreq; // frequency values for the scanning in Hz
public:
AOTF_Controller(void);
~AOTF_Controller(void);
AOTF_Controller::Error connect();
AOTF_Controller::Error disconnect();
AOTF_Controller::Error init();
AOTF_Controller::Error setFreq(float freq); // for frequency value in MHZ (precision to the 3rd decimal i.e. KHz)
AOTF_Controller::Error setFreq(long freq); // for frequency value in Hz
AOTF_Controller::Error setGain(int gain);
AOTF_Controller::Error reset();
AOTF_Controller::Error setScanningFreq(float _startFreq, float _endFreq, int numOfFrames);
AOTF_Controller::Error increaseFreq();
};
//Aotf_Controller.cpp
#include "StdAfx.h"
#include "AOTF_Controller.h"
AOTF_Controller::AOTF_Controller(void)
{
currentGain = 0;
currentFreq = 0;
startFreq = 0;
endFreq = 0;
deltaFreq = 0;
hAotfController = NULL;
}
AOTF_Controller::~AOTF_Controller(void)
{
}
AOTF_Controller::Error AOTF_Controller::connect()
{
int iInstance = 0;
hAotfController = AotfOpen(iInstance);
if (!hAotfController)
{
return CONNECTION_ERROR;
}
else
{
return SUCCESSFUL;
}
}
AOTF_Controller::Error AOTF_Controller::disconnect()
{
if (!AotfClose (hAotfController))
{
return DISCONNECTION_ERROR;
}
else
{
hAotfController = NULL;
return SUCCESSFUL;
}
}
AOTF_Controller::Error AOTF_Controller::init()
{
std::string ampCom="dds a 0 16383\r"; //Command to set the amplitude parameter to the max
std::string modCom="mod dac * 16383\r";//Command to set the dac parameter to the max
int gain = 255; // set the gain to the max
if (!AotfWrite(hAotfController, ampCom.length(), (char *)ampCom.c_str()))
{
return Error::INIT_ERROR;
}
if (!AotfWrite(hAotfController, modCom.length(), (char *)modCom.c_str()))
{
return INIT_ERROR;
}
setGain(gain);
return SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::reset()
{
std::string resetCom = "dds reset\r";
if(!AotfWrite(hAotfController, resetCom.length() , (char *)resetCom.c_str()))
{
return RESET_ERROR;
}
return SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::setFreq(float freq)
{
long freqHz = (long)freq*CONVERSION_MHZ_TO_HZ;
setFreq(freqHz);
return SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::setFreq(long freq)
{
std::ostringstream oss; //stream to build the string
//building the string for the Frequency
oss << "dds f 0 !" << std::fixed << std::setprecision(0) << freq << "\r";
std::string freqCom = oss.str();
//send command to the AOTF
if(!AotfWrite(hAotfController, freqCom.length(), (char *) freqCom.c_str())) // set the frequency (80-120)
{
return SET_ERROR;
}
currentFreq = freq; // update monitoring variable in HZ
return Error::SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::setGain(int gain)
{
std::ostringstream oss; //stream to build the string
//building the string for the Gain
oss << "dds gain -p* * " << gain << "\r";
std::string gainCom = oss.str();
//send command to the AOTF
if(!AotfWrite(hAotfController, gainCom.length(), (char * )gainCom.c_str())) // set the gain (0-255)
{
return SET_ERROR;
}
currentGain = gain;
return SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::setScanningFreq(float _startFreq, float _endFreq, int numOfFrames)
{
float FreqRange = (_endFreq - _startFreq); //calculate range
//calculate DeltaFrequency (frequency increase after each captured frame)
deltaFreq = (long) ((FreqRange/(float)(numOfFrames-1))*(float)CONVERSION_MHZ_TO_HZ); //conversion from MHz to Hz
startFreq = (long) (_startFreq*CONVERSION_MHZ_TO_HZ);
endFreq = (long) (_endFreq*CONVERSION_MHZ_TO_HZ);
setFreq(_startFreq);
return SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::increaseFreq()
{
if (deltaFreq ==0)
{
return SET_ERROR;
}
long newFreq = currentFreq + deltaFreq;
std::ostringstream oss;
oss << "dds f 0 !" << std::fixed << std::setprecision(0) << newFreq << "\r";
std::string freqCom = oss.str();
//send command to the AOTF
if(!AotfWrite(hAotfController, freqCom.length(), (char *)freqCom.c_str())) // set the frequency (80-120)value
{
return SET_ERROR;
}
currentFreq = newFreq;
return SUCCESSFUL;
}
I'm writing a server and I wanted to use XML with my Java client. I'm using CygWin with XercesC 3.1.1 for my development test and this works fine (I looped 30000 with this function and had no crash). However, on my target machine it's running HP-UX with XercesC 2.7. To implement the differences in the XercesC implementation I wrote a separate class to handle each version.
When I try to run the code with XercesC 2.7. I always get a NULL pointer when I try to create the DOMWriter, and a SIGABORT when trying again.
Since I couldn't find anyything on google I hope that someone can shed some light on what I'm doing wrong here. I've been looking at the sample code provided with the XercesC souorce, and I also have some production code from fellow programmers, and I can't see any difference for the live of it.
I tried to create an SSCE which is a bit long, but it is the shortest sample that I could create.
xml_serialize.h
#ifndef XML_SERIALIZE_H_
#define XML_SERIALIZE_H_
#include <string>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/dom/DOM.hpp>
#if defined(XERCES_NEW_IOSTREAMS)
#include <iostream>
#else
#include <iostream.h>
#endif
#include <xercesc/util/OutOfMemoryException.hpp>
class XStr
{
public :
// -----------------------------------------------------------------------
// Constructors and Destructor
// -----------------------------------------------------------------------
XStr(const char* const toTranscode)
{
// Call the private transcoding method
fUnicodeForm = xercesc::XMLString::transcode(toTranscode);
}
~XStr()
{
xercesc::XMLString::release(&fUnicodeForm);
}
// -----------------------------------------------------------------------
// Getter methods
// -----------------------------------------------------------------------
const XMLCh* unicodeForm() const
{
return fUnicodeForm;
}
private :
// -----------------------------------------------------------------------
// Private data members
//
// fUnicodeForm
// This is the Unicode XMLCh format of the string.
// -----------------------------------------------------------------------
XMLCh* fUnicodeForm;
};
#define X(str) XStr(str).unicodeForm()
std::string fromXMLString(XMLCh *oXMLString);
class XMLSerialize
{
private:
xercesc::DOMImplementation *mImpl;
protected:
xercesc::DOMImplementation *getDOMImplementation(void);
public:
XMLSerialize(void);
virtual ~XMLSerialize(void);
public:
/**
* Creates an empty DOM
*/
xercesc::DOMDocument *createDocument(const std::string &oDocumentName);
/**
* Parses an XML from a string.
*/
xercesc::DOMDocument *parseDocument(const std::string &oDocumentName, std::string const &oReferenceId);
/**
* Serializes the document into a string
*/
int serialize(xercesc::DOMDocument *oDocument, std::string &oXMLOut, bool bDocumentRelease = true);
};
#endif /* XML_SERIALIZE_H_ */
xml_serialize.cpp
#include <xercesc/util/XMLString.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/util/TransService.hpp>
#include <xercesc/framework/MemBufFormatTarget.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>
#include <sstream>
#include <vector>
#include <iostream>
#include "xml_serialize.h"
int serializeEnvironment(void);
XMLSerialize *serializer = NULL;
XMLSerialize::XMLSerialize()
{
mImpl = xercesc::DOMImplementationRegistry::getDOMImplementation(X("Core"));
}
XMLSerialize::~XMLSerialize()
{
}
xercesc::DOMDocument *XMLSerialize::createDocument(const std::string &oDocumentName)
{
if(mImpl == NULL)
return NULL;
xercesc::DOMDocument *doc = mImpl->createDocument(
0, // root element namespace URI.
X(oDocumentName.c_str()), // root element name
0); // document type object (DTD).
if(doc == NULL)
return NULL;
return doc;
}
int XMLSerialize::serialize(xercesc::DOMDocument *oDocument, std::string &oXMLOut, bool bDocumentRelease)
{
int result = 0;
XMLCh *xmlUnicode = NULL;
char *strXML = NULL;
xercesc::DOMWriter *serializer = NULL;
if(mImpl == NULL)
{
oXMLOut = "ERROR: XercesC DOMImplementationRegistry not initialized";
result = 1;
goto Quit;
}
serializer = ((xercesc::DOMImplementationLS*)mImpl)->createDOMWriter();
if(serializer == NULL)
{
oXMLOut = "ERROR: XercesC unable to instantiate a DOMWriter!";
result = 2;
goto Quit;
}
xmlUnicode = serializer->writeToString(*oDocument);
strXML = xercesc::XMLString::transcode(xmlUnicode);
oXMLOut = strXML;
if(bDocumentRelease == true)
oDocument->release();
result = 0;
Quit:
if(strXML != NULL)
xercesc::XMLString::release(&strXML);
if(xmlUnicode != NULL)
xercesc::XMLString::release(&xmlUnicode);
if(serializer != NULL)
serializer->release();
return result;
}
int serializeEnvironment(void)
{
int errorCode = 0;
xercesc::DOMElement *rootElem = NULL;
xercesc::DOMElement *item = NULL;
xercesc::DOMElement *element = NULL;
xercesc::DOMText *nameNode = NULL;
xercesc::DOMCDATASection *dataNode = NULL;
std::string xml;
try
{
xercesc::DOMDocument *doc = serializer->createDocument("EnvironmentList");
if(doc == NULL)
return 1;
rootElem = doc->getDocumentElement();
std::vector<std::pair<std::string, std::string> > env;
for(int i = 0; i < 5; i++)
{
std::string key;
std::string value;
std::stringstream ss;
ss << "KEY";
ss << i;
ss >> key;
ss.clear();
ss << "VALUE";
ss << i;
ss >> value;
ss.clear();
env.push_back(std::make_pair(key, value));
}
for(std::vector<std::pair<std::string, std::string> >::const_iterator it = env.begin(); it != env.end(); ++it)
{
std::pair<std::string, std::string>entry = *it;
std::string name = entry.first;
std::string value = entry.second;
if(value.empty())
value = "";
item = doc->createElement(X("item"));
rootElem->appendChild(item);
element = doc->createElement(X("item"));
nameNode = doc->createTextNode(X(name.c_str()));
item->appendChild(element);
element->appendChild(nameNode);
element = doc->createElement(X("item"));
dataNode = doc->createCDATASection(X(value.c_str()));
item->appendChild(element);
element->appendChild(dataNode);
}
errorCode = serializer->serialize(doc, xml);
std::cout << xml << std::endl;
doc->release();
errorCode = 0;
}
catch (const xercesc::OutOfMemoryException&)
{
XERCES_STD_QUALIFIER cerr << "OutOfMemoryException" << XERCES_STD_QUALIFIER endl;
errorCode = 2;
}
catch (const xercesc::DOMException& e)
{
XERCES_STD_QUALIFIER cerr << "DOMException code is: " << e.code << XERCES_STD_QUALIFIER endl;
errorCode = 3;
}
catch (...)
{
XERCES_STD_QUALIFIER cerr << "An error occurred creating the document" << XERCES_STD_QUALIFIER endl;
errorCode = 4;
}
return errorCode;
}
int main()
{
xercesc::XMLPlatformUtils::Initialize();
serializer = new XMLSerialize();
int error = 0;
for(int i = 0; i < 2; i++)
{
std::cout << "Serializing:" << i << " ... " << std::endl;
if((error = serializeEnvironment()) != 0)
std::cout << "ERROR" << error << std::endl;
std::cout << "Done" << std::endl;
}
xercesc::XMLPlatformUtils::Terminate();
return 0;
}
output
Serializing:0 ...
ERROR: XercesC unable to instantiate a DOMWriter!
Done
Serializing:1 ...
aCC runtime: pure virtual function called for class "xercesc_2_7::DOMImplementationLS".
Abort(coredump)
update
I finally managed to compile 2.7 for cygwin and tested the above code there. This works fine, so there must be some problem with the HP-UX environment.
I was compiling the code with gcc and aparently the xerces library was compiled with aCC. So nopw I switched to aCC in my makefile and now it works.
One should expect that the produced libraries are compatible, but apparently this is not the case. So the above code is actually correct.