|
If you use Visual Studio there is an ATL Service Application Wizard that generates boiler plate project for creating a Windows Service.
Of course also on MSDN you will find more information like samples etc., for using the ATL Service wizard.
|
|
|
|
|
I've very recently started to build an app that works with some db items and having seen something sort of like it in php, tried to implement a DB -> object class.
But seeing that I'm kind of ... erm, let's say noobish and used pointers extensively in the class I've decided to try and get some feedback on if the code has some glaring big bad problems from my coding practices side that might let it work ok for 1 example or 2 but that could turn very ugly in some circumstances.
Background:
1. This will act as a base class, each table in the db will implement a new class actualyl defining values for field names, field <-> attribute, links to other objects etc.
2. Will be in a multithreaded app but while different instances will be used in different threads, 1 instance won't be simultaneously used in 2 threads, at least that's what I believe atm.
3. Connection pointer is global, kept alive forever if needed.
4. Not even close to finished, not even current methods, still some error checking to do and possibly more.
So, all I want is if possible some pointers to stuff I terribly messed up and should avoid doing in my code from now on. Basicly learned all from C/C++ on my own from my own code, with what php experience I had and the 6-7 years of experience doing algorithms in pascal, so my approach to solid programming didn't even include threads, avoiding memory "destruction", pointers and all the nice stuff c/c++ on windows has to offer.
Next post should possibly contain 2 more listings, this class' header and a derived class.
DBItem.cpp
<code>
#include "stdafx.h"
#include "DBItem.h"
#include "DB_Obj1.h"
DBItem::DBItem(int nId, _ConnectionPtr pConnectionGeneral)
{
pConnDB = pConnectionGeneral;
pRstDB.CreateInstance(__uuidof(Recordset));
nIid = nId;
}
DBItem::~DBItem()
{
pRstDB->Close();
pRstDB.Release();
pRstDB.Detach();
ds.mAttr.clear();
ds.mAttrFields.clear();
ds.mAttrLoaded.clear();
ds.mAttrModified.clear();
ds.mDeps.clear();
ds.mLinks.clear();
ds.sIdField.~basic_string();
ds.sTableName.~basic_string();
ds.sTittleAttr.~basic_string();
ds.sTreeLink.~basic_string();
while (!mMessages.empty())
{
mMessages.pop();
}
}
BOOL DBItem::Load()
{
char *sztempQuery;
string sQuery, sFldName;
int i;
FieldPtr pField;
FormLoadQuery(&sztempQuery);
sQuery = sztempQuery;
free(sztempQuery);
if (ExecuteQuery(sQuery))
{
for (i = 0; i < pRstDB->Fields->Count; i++)
{
pField = pRstDB->Fields->GetItem(_variant_t((long)i, VT_I4));
sFldName = pField->Name;
ds.mAttr[ds.mAttrFields[sFldName]] = pField->Value;
ds.mAttrLoaded[ds.mAttrFields[sFldName]] = TRUE;
}
}
else
{
AddMessage(DB_ERROR, "Error while executing load query. Check previous message!");
return FALSE;
}
return TRUE;
}
_variant_t DBItem::GetAttr(string sAttr)
{
_variant_t vAttr;
if (nIid == 0)
{
vAttr.vt = VT_NULL;
return vAttr;
}
if (!ds.mAttrLoaded[sAttr])
{
if (!Load())
{
vAttr.vt = VT_NULL;
}
else
{
vAttr = ds.mAttr[sAttr];
}
}
else
{
vAttr = ds.mAttr[sAttr];
}
return vAttr;
}
BOOL DBItem::ExecuteQuery(string sQuery)
{
try
{
pRstDB = pConnDB->Execute(sQuery.c_str(), NULL, adCmdText);
}
catch (_com_error &e)
{
AddMessage(DB_EXCEPTION, "Exception in DBItem::ExecuteQuery(), Class '" + GetClass() + "', ID " + ToString(nIid) + " Error: " + (string)e.ErrorMessage());
return FALSE;
}
return TRUE;
}
void DBItem::AddMessage(int nMsgType, string sMessage)
{
string stempMessage;
stempMessage = ToString(nMsgType) + sMessage;
mMessages.push(stempMessage);
}
string DBItem::GetName()
{
_variant_t vVar;
string stempName = "";
vVar = GetAttr(ds.sTittleAttr);
try
{
stempName = vVar.operator _bstr_t().operator const char *();
}
catch (_com_error &e)
{
AddMessage(DB_EXCEPTION, "Exception in DBItem::GetName(), Class '" + GetClass() + "', ID " + ToString(nIid) + " Error: " + (string)e.ErrorMessage());
stempName = "";
}
return stempName;
}
DBItem *DBItem::GetObject(string sAttr)
{
DBItem *mliInstance;
_variant_t vIdAttr;
unsigned long dInstId;
vIdAttr = GetAttr(sAttr);
dInstId = vIdAttr.operator long();
mliInstance = GetInstance(ds.mLinks[sAttr], dInstId);
return mliInstance;
}
DBIList *DBItem::GetInstances()
{
DBIList *pVector;
DBItem *mliInstance;
char *sztempQuery;
string sQuery;
unsigned long ulID, ulCount;
long i;
FieldPtr pField;
FormGetIDsQuery(&sztempQuery);
sQuery = sztempQuery;
free(sztempQuery);
if (ExecuteQuery(sQuery))
{
ulCount = pRstDB->Fields->Count;
pVector = new DBIList(ulCount);
for (i = 0; i < pRstDB->Fields->Count; i++)
{
pField = pRstDB->Fields->GetItem(_variant_t((long)i, VT_I4));
ulID = pField->Value.ulVal;
mliInstance = GetInstance(GetClass(), ulID);
pVector->push_back(mliInstance);
}
return pVector;
}
else
{
AddMessage(DB_ERROR, "Error while executing ID query. Check previous message!");
return NULL;
}
}
string DBItem::GetClass()
{
return (string)"DBItem";
}
DBItem *DBItem::GetInstance(string sClassName, unsigned long nId)
{
if (sClassName == "DB_Obj1")
return new DB_Obj1(nId, pConnDB);
return NULL;
}
void DBItem::FormLoadQuery(char **szQuery)
{
string stempQuery;
stempQuery = "SELECT * FROM ";
stempQuery += ds.sTableName;
stempQuery += " WHERE ";
stempQuery += ds.sIdField;
stempQuery += "=";
stempQuery += ToString(nIid);
*szQuery = (char *) malloc(stempQuery.length() + 1);
if (*szQuery == NULL)
{
}
else
{
memset(*szQuery, 0, stempQuery.length() + 1);
memcpy(*szQuery, stempQuery.c_str(), stempQuery.length());
}
}
void DBItem::FormGetIDsQuery(char **szQuery)
{
string stempQuery;
stempQuery = "SELECT "
stempQuery += ds.sIdField;
stempQuery += " FROM ";
stempQuery += ds.sTableName;
*szQuery = (char *) malloc(stempQuery.length() + 1);
if (*szQuery == NULL)
{
}
else
{
memset(*szQuery, 0, stempQuery.length() + 1);
memcpy(*szQuery, stempQuery.c_str(), stempQuery.length());
}
}
string DBItem::ToString(int nConvertable)
{
string stempConvert;
char *sztempConvert;
sztempConvert = (char *) malloc(16);
memset(sztempConvert, 0, 16);
_itoa(nConvertable, sztempConvert, 10);
stempConvert = sztempConvert;
free(sztempConvert);
return stempConvert;
}
string DBItem::ToString(long nConvertable)
{
string stempConvert;
char *sztempConvert;
sztempConvert = (char *) malloc(16);
memset(sztempConvert, 0, 16);
_ltoa(nConvertable, sztempConvert, 10);
stempConvert = sztempConvert;
free(sztempConvert);
return stempConvert;
}
</code>
modified on Friday, December 07, 2007 4:27:26 AM
|
|
|
|
|
As posted earlier, 2 more listings, header for class and derived class.
DBItem.h
<code>#define DB_ERROR 1
#define DB_EXCEPTION 2
class DBItem;
typedef pair<string, string> ssPair;
typedef vector<DBItem*> DBIList;
struct DataStructure
{
map<string, _variant_t> mAttr;
map<string, BOOL> mAttrLoaded;
map<string, BOOL> mAttrModified;
map<string, string> mAttrFields;
map<string, string> mLinks;
map<string, ssPair> mDeps;
string sIdField;
string sTableName;
string sTittleAttr;
string sTreeLink;
};
class DBItem
{
public:
DBItem(int nId, _ConnectionPtr pConnectionGeneral = NULL);
virtual ~DBItem();
_variant_t GetAttr(string sAttr);
string GetName();
DBItem *GetObject(string sAttr);
DBIList *GetInstances();
virtual string GetClass();
protected:
DBItem *GetInstance(string sClassName, unsigned long nId);
DataStructure ds;
private:
_ConnectionPtr pConnDB;
_RecordsetPtr pRstDB;
int nIid;
stack<string> mMessages;
BOOL bNoLogging;
BOOL Load();
void FormLoadQuery(char **szQuery);
void FormGetIDsQuery(char **szQuery);
BOOL ExecuteQuery(string sQuery);
void AddMessage(int nMsgType, string sMessage);
string ToString(int nConvertable);
string ToString(long nConvertable);
};</code>
DB_Obj1.cpp
<code>#include "stdafx.h"
#include "DB_Obj1.h"
DB_Obj1::DB_Obj1(int nId, _ConnectionPtr pConnectionGeneral) : DBItem(nId, pConnectionGeneral)
{
_variant_t vtNull;
vtNull.vt = VT_NULL;
ds.mAttr["Id"] = vtNull;
ds.mAttr["Name"] = vtNull;
ds.mAttr["State"] = vtNull;
ds.mAttrFields["IdObj"] = "Id";
ds.mAttrFields["ObjName"] = "Name";
ds.mAttrFields["CurrentState"] = "State";
ds.mAttrLoaded["Id"] =
ds.mAttrLoaded["Name"] =
ds.mAttrLoaded["State"] =
ds.mAttrModified["Id"] =
ds.mAttrModified["Name"] =
ds.mAttrModified["State"] = FALSE;
ds.mLinks["State"] = "DB_StateObj";
ds.mDeps["someone_depends_on_me_somehow"] = make_pair((string)"DB_SomeObj", (string)"IdObj1");
ds.sIdField = "IdObj";
ds.sTableName = "objects1";
ds.sTittleAttr = "Name";
ds.sTreeLink = "";
}
DB_Obj1::~DB_Obj1()
{
}
string DB_Obj1::GetClass()
{
return (string)"DB_Obj1";
}</code>
modified on Friday, December 07, 2007 4:30:04 AM
|
|
|
|
|
VC6 - WTL 8
I'm currently updating my software UI to Vista and I wonder what the Windows Explorer "toolbar" is (Vista Aero style) ?
I would like to show my coolbar's toolbars with the same look as the Windows Explorer one (the one with Organize, view,...). But at the moment my toolbars look like the menu one.
When I drag MiniSpy over the "toolbar" (the one with Organize, view,...) it says class name is DirectUIHWND.
Does it mean it is an owner drawn component or is it the famous Ribbon bar control ?
The menu itself has the ToolBarWindow32 class and a different look, so that toolbar is obviously something different.
Any clue of the control name, style, manifest setting,... ?
Yarp
www.senosoft.com
Yarp
http://www.senosoft.com/
|
|
|
|
|
Direct UI is an internal MS library that they have not documented.
|
|
|
|
|
Thanks for the info Mike. Fortunately I was able to change my Coolbar's look thanks to Bjarn Viksoe's photo gallery implementation:
http://www.viksoe.dk/code/photothing.htm[^]
Yarp
http://www.senosoft.com/
|
|
|
|
|
Hi all,
I have been trying to determine the ideal rectangle for the rich edit control text. but failed.
Here is the thing that i did..
Method 1:
HRESULT SetToNaturalSize(LONG w) {
HDC hdc = ::GetDC(parent_window_);
LONG x_per_inch = GetDeviceCaps(hdc, LOGPIXELSX);
LONG y_per_inch = GetDeviceCaps(hdc, LOGPIXELSY);
LONG width = (w * HIMETRIC_PER_INCH + x_per_inch - 1) / x_per_inch;
LONG height = LONG_MAX;
SIZEL sizel = { LONG_MAX, LONG_MAX };
SetMapMode(hdc, MM_ANISOTROPIC);
SetWindowExtEx(hdc, HIMETRIC_PER_INCH, HIMETRIC_PER_INCH, NULL);
SetViewportExtEx(hdc, x_per_inch, y_per_inch, NULL);
HRESULT hr = text_services_->TxGetNaturalSize(DVASPECT_CONTENT, hdc, NULL,
NULL, TXTNS_FITTOCONTENT, &sizel, &width, &height);
SetMapMode(hdc, MM_TEXT);
::ReleaseDC(parent_window_, hdc);
if (SUCCEEDED(hr)) {
width = (width * x_per_inch + HIMETRIC_PER_INCH - 1) / HIMETRIC_PER_INCH;
height = (height * y_per_inch + HIMETRIC_PER_INCH - 1) / HIMETRIC_PER_INCH;
text_rc_.left = 0;
text_rc_.right = width;
text_rc_.top = 0;
text_rc_.bottom = height;
}
return hr;
}
Method 2:
HRESULT SetToNaturalSize(LONG w) {
HDC hdc = ::GetDC(parent_window_);
long width;
long height;
width = w;
height = 1;
SIZEL sz;
sz.cx = width;
sz.cy = height;
HRESULT hr = text_services_->TxGetNaturalSize(DVASPECT_CONTENT, hdc, NULL, NULL,
TXTNS_FITTOCONTENT, &sz, &width, &height);
::ReleaseDC(parent_window_, hdc);
if (SUCCEDED(hr)) {
text_rc_.SetRectEmpty();
text_rc_.right = width;
text_rc_.bottom = height;
}
return hr;
}
After that i call the TxDraw to draw the text with the rectangle text_rc_.
Both of them works fine(most times) under DPI set at 96, but when i set it to 120 then some of the text doesnt get drawn. I also observed that the function TxGetNaturalSize() doesnt return the same value for the same text each time.
Any idea where i could go wrong? Its driving me crazy..
modified on Wednesday, December 05, 2007 7:48:36 AM
|
|
|
|
|
Hi All,
When creating a shell extension Dll, is it possible to obtain the HWND of the ContextMenu *before* InvokeCommand? If not, how does one call DrawMenuBar() after inserting a menu item into a menu using InsertMenu()? MSDN states we must call DrawMenuBar()[1]:The application must call the DrawMenuBar function whenever a menu changes, whether or not the menu is in a displayed window. Jeff
[1] InsertMenu Function[^]
|
|
|
|
|
You don't have to call DrawMenuBar() . You aren't the owner of the menu, Explorer is, so calling that function isn't your responsibility.
|
|
|
|
|
Does the string class have something similar to the split() functionality available in the .Net framework? or would I have to actually split the string manually by looping through the character array?
"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." - Rick Cook
"There is no wealth like knowledge, no poverty like ignorance." Ali ibn Abi Talib
"Animadvertistine, ubicumque stes, fumum recta in faciem ferri?"
|
|
|
|
|
The STL string class doesn't have a split function.
Mustafa Ismail Mustafa wrote: would I have to actually split the string manually by looping through the character array
You could do that, or you could do yourself a favour and use the split function in the Boost string algorithm library[^]. If you end up doing it manually, though, you'll probably benefit from using the STL string's find_first_of method?
|
|
|
|
|
Gaa, you beat me to it! I'm not fast enough
Florin Crişan
|
|
|
|
|
Sorry for the late reply but I had to leave for a bit. Thanks I was contemplating installing boost, but I figured I'd hit the standard STL before I do that. Besides, this is only for my MSc. PoC for my Advanced Algorithms lecture.
As is, many thanks to you and Florin!
However, I'm now facing something new.
This is a partial view of what I have:
try
{
ListOfSubsets().push_back("{}");
list<char*>::iterator pos;
for(pos = ListOfElements().begin(); pos != ListOfElements().end(); ++pos)
{
cout << *pos << endl;
}
}
catch(exception ex)
{
cout << "an error has occurred: " << endl;
cout << ex.what() << endl;
return;
}
with these defined in the header:
private:
list<char*> _ListOfElements;
list<char*> _ListOfSubsets;
protected:
list<char*> ListOfElements(void) const
{
return _ListOfElements;
}
void set_ListOfElements(list<char*> listOfElements)
{
_ListOfElements = listOfElements;
}
list<char*> ListOfSubsets(void) const
{
return _ListOfSubsets;
}
void set_ListOfSubsets(list<char*> listOfSubsets)
{
_ListOfSubsets = listOfSubsets;
}
It builds no problem, but when it runs, at the start of iterating through the list ListOfElements, it throws the following error:
Debug Assertion failed! Expression: list iterators incompatible.
no exception is thrown, no errors during building and the iterators are of the same type.
Any clues?
"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." - Rick Cook
"There is no wealth like knowledge, no poverty like ignorance." Ali ibn Abi Talib
"Animadvertistine, ubicumque stes, fumum recta in faciem ferri?"
|
|
|
|
|
Sorry for the late answer, I haven't been accessing the forums lately.
I must admit I had to actually try it in the debugger to understand what is happening
The problem is that your ListOfElements function always returns a copy of the list. So ListOfElements().begin() and ListOfElements().end() are two iterators pointing to different containers.
You have to rememeber that, unlike C#, Java and many others, C++ does not treat variables as references. X x is not a reference to an X, but an object on the stack, just like int x .
You should modify your function's signature to const list & ListOfElements(void) const . Just list & will not work, since your function is const . This will still enable you to copy the container, when you want: list a = obj.ListOfElements() .
A note about style: don't use names starting with an underscore. From MSDN[^]:
Use of two sequential underscore characters ( __ ) at the beginning of an identifier, or a single leading underscore followed by a capital letter, is reserved for C++ implementations in all scopes. You should avoid using one leading underscore followed by a lowercase letter for names with file scope because of possible conflicts with current or future reserved identifiers.
Florin Crisan
|
|
|
|
|
aha!
Thank you VERY much Florin. You have no idea what kind of headache this bug has been causing me. Eventually I gave up on it and finished my homework in C# (I'm an MSc. Student).
But I still don't understand, why a reference has to be returned?
Like here:
Florin Crisan wrote: const list & ListOfElements(void) const
instead of a plain
list ListOfElements(void) const ?
I'm posting this before trying it out to be frank, but I'll be sure to test it out first thing in the morning, its 23:37 here and I've had a horrible day at work then university. :dead tired:
Again Florin, thanks a million!
"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." - Rick Cook
"There is no wealth like knowledge, no poverty like ignorance." Ali ibn Abi Talib
"Animadvertistine, ubicumque stes, fumum recta in faciem ferri?"
|
|
|
|
|
Mustafa Ismail Mustafa wrote: But I still don't understand, why a reference has to be returned?
Like here:
Florin Crisan wrote:
const list & ListOfElements(void) const
instead of a plain
list ListOfElements(void) const
?
Because you'll return a *copy* of the list every time if you return by value rather than reference. This means that two calls to ListOfElements return different lists, so (as you've already found) their iterators won't be compatible. In addition, returning a new copy every time is expensive in time and memory - you don't want to copy!
Returning by reference is equivalent to what C# does when you return an object from a method - objects are only ever passed around by reference in C# as all objects are heap allocated and garbage collected - that's not true for C++.
|
|
|
|
|
aha!
Stuart, thank you, you've cleared it all up in my mind.
You and Florin have done me a massive favor.
One last question. Since it returns a copy, why are they incompatible? I'd expect them to be compatible, albeit this is scary since you're no longer sure about data correctness. In other words, I can see how this might render the data incorrect (assuming the original is changed but you're reading from the copy) as well as its bad design, but surely the iterator since it is of the same time as the iterator of the original would be compatible.
"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." - Rick Cook
"There is no wealth like knowledge, no poverty like ignorance." Ali ibn Abi Talib
"Animadvertistine, ubicumque stes, fumum recta in faciem ferri?"
|
|
|
|
|
Well, the thing is, the iterators are incompatible. An iterator is not an index into the container; it's more like a pointer to a specific location. Each iterator is only valid for one container. If you try to compare two iterators pointing to two different containers, it will obviously not work.
Actually, I think it's great that the implementation complains that something's wrong (although the message isn't really obvious). You might have had a very hard to spot bug otherwise.
C# and C++ have a lot of things in common, but still they are quite different. If you are serious about learning it, I can recommend Stroustrup[^]'s The C++ Programming Language[^]. It worked for me
Florin Crisan
|
|
|
|
|
None that I know of. But you can always try boost::algorithm::string::split[^].
See also the example[^].
Boost[^] is a free, peer-reviewed collection of portable C++ source libraries, started by a number of members from the C++ standardisation committee (they've been joined by others in the meantime), aiming to establish "existing practice" and provide reference implementations so that Boost libraries are suitable for eventual standardization. (Yes, the words are from the site ) There is a nice Background Information page[^].
A Windows installer is available here[^].
Florin Crişan
|
|
|
|
|
I wanna create a screen scrapper for the web in WTL. But I'm having a hard time finding a class that will let me access a web url to do it. I know in C# theres WebRequest. and I was wondering how would I go about doing it?
|
|
|
|
|
ATL got some internet-related classes added recently (I forget if it was VC7 or 8). Maybe there's something there for you.
|
|
|
|
|
Hi All,
I have a ActiveX component created using VC++.Net and want to include that in a ATL service created in .Net. But I am not able to add that and use the methods and functions of the ActiveX. Please can someone tell me how to access that ActiveX using Visual Studio 2005.
Thanks
Alpa
|
|
|
|
|
Hi All
I have developed a snapIn.at run time I have an object of class CSnapInItem.
I need to extract the classname of that object that inherit CSnapInItem class at run time.
I have tried CSnapInItem* pItem
typeid(*pItem).name();
but its not wrking....throwing an exception..at run time,...plzz help me..hoe to get the class name at run time.
thanks in advance.
Rashmi
|
|
|
|
|
|
Also make sure your type is a polymorphic type (that is, it has at least one virtual function).
As a rule of thumb, always read the MSDN information (paying extra attention the fine print) when not sure about something.
This article[^] explains quite well how typeid works.
Florin Crişan
|
|
|
|
|