|
The VC6 implementation of std::map's is very annoying across DLL boundaries.
It uses some static members to keep track of sentinel values for the map. This means each DLL that uses a std::map will have different values, and causes the tree walking to much up because those values never match up.
To fix this problem for me, I used STLPort. http://www.stlport.org[^] It solved all my stl dll problems, and even got a bonus hash-map to use. Yay!
The other alternative (which I was using for a while) was to never pass stl containers around, and just try to have a plain interface wrapping them all. It wasn't much fun.
Phil
|
|
|
|
|
Hi, I want to be able to pass back an array of CString's from an ATL Server Web Service to a C# web Form's application.
Any ideas on how to do this?
e.g. here is example code on returning a single string (a BSTR):
namespace MyLabService
{
// all struct, enum, and typedefs for your webservice should go inside the namespace
// IMyLabService - web service interface declaration
//
[
uuid("911E5A7B-194B-4070-B080-36234B341D15"),
object
]
__interface IMyLabService
{
// HelloWorld is a sample ATL Server web service method. It shows how to
// declare a web service method and its in-parameters and out-parameters
[id(1)] HRESULT HelloWorld([out, retval]BSTR *bstrOutput);
};
// MyLabService - web service implementation
//
[
request_handler(name="Default", sdl="GenMyLabWSDL"),
soap_handler(
name="MyLabService",
namespace="urn:MyLabService",
protocol="soap"
)
]
class CMyLabService :
public IMyLabService
{
public:
// This is a sample web service method that shows how to use the
// soap_method attribute to expose a method as a web method
[ soap_method ]
HRESULT HelloWorld(/*[out, retval]*/ BSTR *bstrOutput)
{
CComBSTR bstrOut(L"Hello World");
*bstrOutput = bstrOut.Detach();
return S_OK;
}
}; // class CMyLabService
} // namespace MyLabService
Instead of:
[id(1)] HRESULT HelloWorld([out, retval]BSTR *bstrOutput);
I would like something like:
[id(1)] HRESULT HelloWorld([out, retval]vector<cstring> *Output);
I would really appreciate help on this one!!!!
Cheers,
Tony.
|
|
|
|
|
SAFEARRAY
Don't have a clue how they are handled in C# though. Sorry.
|
|
|
|
|
Use of SOAP 3 will save you a lot of time. Go MSDN and download the kit, look into the sample.
String array can be a comma separated, Recordset, XML format. SAFEARRAY is in fact not more than a struct, why must you stuck with it? Be more creative in solving the problem.
|
|
|
|
|
Is there a way to guarantee that the values inside a multimap are sorted in a certain way? I don't mean just sorting the keys, but values mapped to the same key also sorted by a functor (function object) or anything else? Even though I can retrieve the value_comp functor, I cannot set it because it's defined within the multimap class. This default value_comp just sorts the keys. What I really want is that equal_range returns iterators to sorted values according to my compare functor, but I couldn't find a way to accomplish this. The the values returned by the iterators aren't sorted in any special way that I can contro.
Thanks for any help,
rod
|
|
|
|
|
Well, you can have sort of what you're after by using multiset instead of multimap like the following: Suppose your multimap is originally defined as:
std::multimap<type_a,type_b> So, define a struct holding the two parts of the multimap :
struct pair_ab
{
type_a first;
type_b second;
bool operator<(const pair_ab& x)const
{
if(first<x.first)return true;
if(x.first<first)return false;
return second<x.second;
}
}; and replace your multimap with
std::multiset<pair_ab> Now, this multiset really behaves as a multimap on type_a with the added feature that elements with equivalent first members are further sorted by second . Please report back if this works. Good luck.
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
|
|
|
|
|
It seems like like allocating memory for strings and returning a pointer to the caller would be very efficient.
However, it is considered to be a bad practice to allocate memory in a function and to expect the function caller to be responsible for memory deallocation. (This is how COM manages memory but that is another story.) Managing memory is a challenge. The various string classes in C++ have gone a long way towards resolving string memory problems in C++.
While string classes, such as stls std::basic_string are powerfull, it seems like there is a performance vs. safety trade-off. Sure, performance isn't as much of a concern as it use to be, but if we don't care about performance, we probably should be coding in Java, Perl, VB etc.
Now for some code:
std::basic_string<TCHAR>
SoapFault::GetSoapEnvelopeFault (bool IncludeDetail )
{
TCHAR* Soap = NULL;
TCHAR* SoapElements[3]; SoapElements[1] = NULL;
SoapElements[0] = SOAP_UPPER_ENVELOPE;
SoapElements[1] = this->BuildFaultXml(IncludeDetail);
SoapElements[2] = SOAP_LOWER_ENVELOPE;
Soap = TStrCat(Soap, SoapElements, SoapElements + 3);
delete (SoapElements[1]);
return Soap;
}
The last statement - return Soap - (note that SOAP is a raw TCHAR pointer) causes a new basic_string object to be constructed. A copy constructor is invoked and the contents of Soap are deep-copied to the new basic_string.
So here is the question - How do I return Soap, and construct a new basic_string class that shallow copies the Soap pointer? This would allow me to main my efficieny while retaining the safety of string class.
Ideas and opinions on the approach are welcome.
Links would also help.
thanks
|
|
|
|
|
I was under the impression that almost all implementations of basic_string use reference counted shared buffers internally, so that return is already, essentially, a shallow copy. I could be wrong, though (I have not examined the code myself).
- Mike
|
|
|
|
|
Thanks for the reply Mike,
I think CString reference counts but I don't think basic_string does.
I stepped through the copy-constructor with the debugger. The copy-ctor calls assign() and assign() calls copy().
The copy member function uses memcpy to deep-copy the characters.
I am sure that memcpy of array of characters probably is pretty quick.
I am thinking in terms of big multi-megabyte XML docs.
I have worked with CComBSTR in ATL. You can attach and detach raw BSTRs. When attached - the CComBSTR will manage the lifetime of the underlying BSTR. (The pointer approach). I would be cool if basic_string could do this somehow through the copy constructor.
|
|
|
|
|
I've done some research, and indeed, it appears that many STL implementations have abandoned ref-counted strings due to issues with operator[] and multi-threaded code. Bummer.
On the other hand, it appears that many people have made their own non-standard ref-counted string classes I guess you could also wrap the strings in an auto_ptr or a shared_ptr ...
- Mike
|
|
|
|
|
Thanks for looking into this,
If nothing else, it is interesting to think that there are still problems to be solved concerning something as typical as a string.
I think returning raw allocated memory may be a problem as a general solution.
Now I see why a String in Java is immutable and StringBuffers are utilized for concatenation and such.
Options at this point.
1. Look into some custom string classes that ref count.
2. Look for more options in terms of design.
3. Create a thin string wrapper to ref count and manage memory.
|
|
|
|
|
One other option that I forgot about is to use the std::rope extension to the STL for really large strings, since rope s are still ref-counted and are designed for large chunks of text (at the expense of slow updates to single characters).
http://www.sgi.com/tech/stl/Rope.html[^]
rope doesn't seem to be available in the STL implementations that ship with VS.NET (2k2 or 2k3), nor the Dinkumware implementation they're based on. However, they are available in SGI-based implementations such as STLport.
- Mike
|
|
|
|
|
thanks - will check it out
|
|
|
|
|
I am using stlport 4.5.3 with _STLP_NO_OWN_IOSTREAMS defined in MSVC6 and I get 66 errors with locale. Here is the test program:
#include <string>
using namespace std;
#include <locale>
int main(int argc, char* argv[])
{
return 0;
}
f:\program files\microsoft visual studio\vc98\include\xiosbase(106) : error C2146: syntax error : missing ';' before identifier 'precision'
f:\program files\microsoft visual studio\vc98\include\xiosbase(106) : error C2501: 'streamsize' : missing storage-or type specifiers
f:\program files\microsoft visual studio\vc98\include\xiosbase(107) : warning C4183: 'precision': member function definition looks like a ctor, but name does not match enclosing class
f:\program files\microsoft visual studio\vc98\include\xiosbase(108) : error C2146: syntax error : missing ';' before identifier 'precision'
f:\program files\microsoft visual studio\vc98\include\xiosbase(108) : error C2501: 'streamsize' : missing storage-or type specifiers
f:\program files\microsoft visual studio\vc98\include\xiosbase(111) : warning C4183: 'precision': member function definition looks like a ctor, but name does not match enclosing class
f:\program files\microsoft visual studio\vc98\include\xiosbase(112) : error C2146: syntax error : missing ';' before identifier 'width'
f:\program files\microsoft visual studio\vc98\include\xiosbase(112) : error C2501: 'streamsize' : missing storage-or type specifiers
f:\program files\microsoft visual studio\vc98\include\xiosbase(113) : warning C4183: 'width': member function definition looks like a ctor, but name does not match enclosing class
f:\program files\microsoft visual studio\vc98\include\xiosbase(114) : error C2146: syntax error : missing ';' before identifier 'width'
f:\program files\microsoft visual studio\vc98\include\xiosbase(114) : error C2501: 'streamsize' : missing storage-or type specifiers
f:\program files\microsoft visual studio\vc98\include\xiosbase(114) : error C2061: syntax error : identifier 'streamsize'
f:\program files\microsoft visual studio\vc98\include\xiosbase(117) : warning C4183: 'width': member function definition looks like a ctor, but name does not match enclosing class
f:\program files\microsoft visual studio\vc98\include\locale(171) : error C2664: 'compare' : cannot convert parameter 1 from 'dbg_iter ' to 'const char *'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
x:\stlport\stlport\using\locale(9) : error C2039: 'locale' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(9) : error C2873: 'locale' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(10) : error C2039: 'use_facet' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(10) : error C2873: 'use_facet' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(11) : error C2039: 'has_facet' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(11) : error C2873: 'has_facet' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(29) : error C2039: 'ctype_base' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(29) : error C2873: 'ctype_base' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(30) : error C2039: 'ctype' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(30) : error C2873: 'ctype' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(31) : error C2039: 'ctype_byname' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(31) : error C2873: 'ctype_byname' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(32) : error C2039: 'codecvt_base' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(32) : error C2873: 'codecvt_base' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(33) : error C2039: 'codecvt' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(33) : error C2873: 'codecvt' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(34) : error C2039: 'codecvt_byname' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(34) : error C2873: 'codecvt_byname' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(37) : error C2039: 'num_get' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(37) : error C2873: 'num_get' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(38) : error C2039: 'num_put' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(38) : error C2873: 'num_put' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(39) : error C2039: 'numpunct' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(39) : error C2873: 'numpunct' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(40) : error C2039: 'numpunct_byname' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(40) : error C2873: 'numpunct_byname' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(43) : error C2039: 'collate' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(43) : error C2873: 'collate' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(44) : error C2039: 'collate_byname' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(44) : error C2873: 'collate_byname' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(47) : error C2039: 'time_base' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(47) : error C2873: 'time_base' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(48) : error C2039: 'time_get' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(48) : error C2873: 'time_get' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(49) : error C2039: 'time_get_byname' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(49) : error C2873: 'time_get_byname' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(50) : error C2039: 'time_put' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(50) : error C2873: 'time_put' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(51) : error C2039: 'time_put_byname' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(51) : error C2873: 'time_put_byname' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(54) : error C2039: 'money_base' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(54) : error C2873: 'money_base' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(55) : error C2039: 'money_get' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(55) : error C2873: 'money_get' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(56) : error C2039: 'money_put' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(56) : error C2873: 'money_put' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(57) : error C2039: 'moneypunct' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(57) : error C2873: 'moneypunct' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(58) : error C2039: 'moneypunct_byname' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(58) : error C2873: 'moneypunct_byname' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(61) : error C2039: 'messages_base' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(61) : error C2873: 'messages_base' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(62) : error C2039: 'messages' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(62) : error C2873: 'messages' : symbol cannot be used in a using-declaration
x:\stlport\stlport\using\locale(63) : error C2039: 'messages_byname' : is not a member of '`global namespace''
x:\stlport\stlport\using\locale(63) : error C2873: 'messages_byname' : symbol cannot be used in a using-declaration
Error executing cl.exe.
StdString.exe - 66 error(s), 4 warning(s)
John
|
|
|
|
|
Hi Dears
I have to make a simple COM+ Application programatically to register my ATL COM Component.
Please guide me to build that in VC++ ........
I'll be really thankful.
God bless you.
Kind Regards.
Atif
Watch Your Thoughts for they will become your actions.
Watch Your Actions for they will become your habits.
Watch Your Habits for they will become your beliefs.
Watch Your Beliefs for they will determine your destiny.
|
|
|
|
|
A few simple solutions come to mind.
Assuming your ATL COM component is in-process, you could call LoadLibrary() on the DLL, GetProcAddress() on DllRegisterServer() and then call through the function pointer.
Alternatively, use CreateProcess() to run regsvr32.exe which essentially does the same as the above. I'm not sure if you can rely on regsvr32.exe being part of a "standard" Windows installation.
If your COM component is hosted by an out-of-process server, you can call CreateProcess() on your EXE, passing the "/RegServer" or "/Service" command line argument as required.
HTH
Brad
|
|
|
|
|
I'm looking to implement a DHTML search panel view similar to the XP Explorer Search. Has anyone done so or know of articles?
Thanks, Mike
|
|
|
|
|
Hi,
I have created a composite control using ATL which has a menu and displays as a overlapped window. I want to raise an event when a particular menu item was clicked. For this i have implemented ConnectionPoint interface. The class has a display method for displaying the control.
When i am displaying the control from a visual basic application the control was getting displayed and EVENTS are not raising when a menu item was clicked. Why is this happening. Can anyone please suggest.
Nalini Kanth
e-Logic Solutions Pvt Ltd
|
|
|
|
|
Hi Dears
Kindly Tell me How to run a script (.vbs) in VC++, Please help ....
I'll very be thankful
Atif
Watch Your Thoughts for they will become your actions.
Watch Your Actions for they will become your habits.
Watch Your Habits for they will become your beliefs.
Watch Your Beliefs for they will determine your destiny.
|
|
|
|
|
|
It can be done with VBScript object (ProgID - VBScript) and its IActiveScript**** interfaces. Especially, IActiveScriptParse.
CComPtr< IActiveScript > spScript;
HRESULT hr = spScript.CoCreateInstance( OLESTR("VBScript") );
if( SUCCEEDED(hr) )
{
CComQIPtr< IActiveScriptParse > spParser( spScript );
if( spParser )
{
hr = spScript->SetScriptSite( spScriptSite );
hr = spParser->InitNew();
hr = spScript->SetScriptState( SCRIPTSTATE_STARTED );
hr = spScript->AddTypeLib( CComModule::m_libid, 1, 0, 0L );
hr = spScript->AddNamedItem( OLESTR("Me"), SCRIPTITEM_ISVISIBLE );
...
spScript->Close();
}
}
With best wishes,
Vita
|
|
|
|
|
I have an stl list of pointers to objects.
When I need to insert an object to the list, I new it and push_back its
pointer.
When the list is not needed any more, I iterate through the entire list and
I delete each pointer.
First question: Is there a more elegant way to do this or is my
implementation ok?
Sometimes I wish to copy a pointer for one list into another list, meaning
that the two lists will contain a pointer to the same object.
When the first list is destroyed, I delete all pointers inside it, as
mentioned above.
When the second list is destroyed, I do the same, however my pointers are
already deleted and this of course crashes the program.
My first thought was to implement reference counting on my object, however I
am unsure of where to increment the reference.
The code looks something like this:
std::list<cmyobj*> list1;
std::list<cmyobj*> list2;
CMyObj* pOBJ = new CMyObj;
list1.push_back(pOBJ);
list2.insert(list2.begin(), list1.begin(), list1.end());
// delete all elements in list1
// delete all elements in list2 (crash)
When list2.insert is called, a copy of the pointer from list1 is inserted
into list2.
I will need to increment the reference of the pointer which is inserted,
however I am unsure of how to do this.
Does anyone have a solution to this?
Thanks in advance,
Jeremy Pullicino
C++ Developer
Homepage
|
|
|
|
|
Hi Jeremy,
As you correctly point out, some sort of ref counting is needed to address your problem. IMHO providing CMyObj with the ref counting machinery is not a good idea as this artifact properly does not belong to CMyObj semantics, but rather it is imposed by external conditions (the necessity of storing CMyObj pointers into several containers).
A much cleaner approach is to use some sort of smart pointer that does the ref counting to the objects pointed to and deletes them when the objects are no further referenced. If you feel comfortable with Boost, check Boost Smart Pointers Library[^]: in particular, boost::shared_ptr does exactly what you need.
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
|
|
|
|
|
I highly recommend Loki::SmartPtr[^] for that purpose. Or if you don't feel comfortable with this, use boost::shared_ptr.
|
|
|
|
|
Dear all,
I have a situation like this. For my application i have a bit map, and i wat to set this bitmap cursor in some area of my GUI. the bit map to be set as the cursor is not the original one from the resource, before that i want to rotate the bitmap according to some events like mouse scroll event, ok i can make it rotate the bitmap using the code,HBITMAP CRotateimageDlg::GetRotatedBitmapNT(HBITMAP hBitmap, float radians, COLORREF clrBack)
{
// Create a memory DC compatible with the display
CDC sourceDC, destDC;
sourceDC.CreateCompatibleDC( NULL );
destDC.CreateCompatibleDC( NULL );
// Get logical coordinates
BITMAP bm;
::GetObject( hBitmap, sizeof( bm ), &bm );
float cosine = (float)cos(radians);
float sine = (float)sin(radians);
// Compute dimensions of the resulting bitmap
// First get the coordinates of the 3 corners other than origin
int x1 = (int)(bm.bmHeight * sine);
int y1 = (int)(bm.bmHeight * cosine);
int x2 = (int)(bm.bmWidth * cosine + bm.bmHeight * sine);
int y2 = (int)(bm.bmHeight * cosine - bm.bmWidth * sine);
int x3 = (int)(bm.bmWidth * cosine);
int y3 = (int)(-bm.bmWidth * sine);
int minx = min(0,min(x1, min(x2,x3)));
int miny = min(0,min(y1, min(y2,y3)));
int maxx = max(0,max(x1, max(x2,x3)));
int maxy = max(0,max(y1, max(y2,y3)));
int w = maxx - minx;
int h = maxy - miny;
// Create a bitmap to hold the result
HBITMAP hbmResult = ::CreateCompatibleBitmap(CClientDC(NULL), w, h);
HBITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );
HBITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );
// Draw the background color before we change mapping mode
HBRUSH hbrBack = CreateSolidBrush( clrBack );
HBRUSH hbrOld = (HBRUSH)::SelectObject( destDC.m_hDC, hbrBack );
destDC.PatBlt( 0, 0, w, h, PATCOPY );
::DeleteObject( ::SelectObject( destDC.m_hDC, hbrOld ) );
// We will use world transform to rotate the bitmap
SetGraphicsMode(destDC.m_hDC, GM_ADVANCED);
XFORM xform;
xform.eM11 = cosine;
xform.eM12 = -sine;
xform.eM21 = sine;
xform.eM22 = cosine;
xform.eDx = (float)-minx;
xform.eDy = (float)-miny;
SetWorldTransform( destDC.m_hDC, &xform );
// Now do the actual rotating - a pixel at a time
destDC.BitBlt(0,0,bm.bmWidth, bm.bmHeight, &sourceDC, 0, 0, SRCCOPY );
// Restore DCs
::SelectObject( sourceDC.m_hDC, hbmOldSource );
::SelectObject( destDC.m_hDC, hbmOldDest );
return hbmResult;
} and can load it in to the image control, but my require ment is another one, how can i load the returned HBITMAP as a cursor?? pls get me if anybody has the idea, or if u have the code snipet pls let me know..
Thanks in advance.
AnuragVelekkattu
|
|
|
|
|