|
Just remembered a potentially useful IDL attribute : custom.
The following is taken from MSDN :
custom
The [custom] attribute creates a user-defined attribute.
[custom(attribute-id, attribute-value),attribute-list] element-type element-name
Use the [custom] attribute to define your own attribute. For example, you might create a string-valued attribute that gives the ProgID for a class.
To retrieve a custom attribute value call one of the following:
ITypeLib2::GetCustData(rguid, pvarVal)
ITypeInfo2::GetCustData(rguid, pvarVal)
ITypeInfo2::GetFuncCustData(index, rguid, pvarVal)
ITypeInfo2::GetVarCustData(index, rguid, pvarval)
ITypeInfo2::GetParamCustData(indexFunc, indexParam, rguid, pvarVal)
|
|
|
|
|
* Note that memory allocated inside a DLL must be released within the same DLL and not in the main application program.
* This is because the HEAP used for the memory allocated in the DLL will be different from the HEAP used by the main application.
|
|
|
|
|
The following is taken from the Technical White Paper "The Basics of Programming Model Design" by Dave Stearns of Microsoft :
You may be confused by the term programming model, but it's really just the correct term for what most people call object model. By programming model I mean the set of interfaces, properties, methods, and events exposed from a component that allows a developer to write programs to manipulate it.
... a good programming model doesn't just expose internal structures—it exposes its functionality at a higher level of abstraction so that the customer (the developer) can concentrate on what he or she wants to do and not on how to accomplish a simple task.
|
|
|
|
|
For a long time, I had a hard time trying to figure out the correct way to handle VARIANT parameters.
It is especially worrisome when VARIANT parameters hold objects like BSTRs, structures (VT_RECORD) and SAFEARRAYs.
Do we need to make copies of these before we insert them into VARIANTs ? And why ? Do we need to destroy these after we have inserted them into VARIANTs ?
It turned out that the answer is simple (albeit not trivial). It is analogous to the principles of reference counting for COM interface pointers. Basically :
1. In a COM method, when you need to pass an object (via a VARIANT) as an [out] parameter, you need to make a copy of it. This is similar to the fact that we AddRef() an interface pointer returned as an [out] parameter.
Hence it follows that once a copy of the object is made and inserted into the VARIANT, you do not delete it. It is the responsibility of the receiving client to delete it in its own time.
2. In a COM method, when you receive an object (via a VARIANT) as an [in] parameter, you can use it in whatever way you like but you must not delete it. This is similar to the fact that you do not Release() an interface pointer passed into a COM method as an [in] parameter.
Visual Basic is a very good tool to test whether your code follows COM standards as outlined above. If you write a COM object in VC++, and you have objects passed as [in] and [out] parameters, write a VB client code to test for robustness.
|
|
|
|
|
When authoring an IDL file, if you wish to refer to some entity defined inside some type library, you must use the importlib statement in the IDL file.
Note the following advise from MSDN :
In most cases you should use the MIDL [import] directive to reference definitions from another .IDL file in your .IDL file. This method provides your type library with all the information from the original file, whereas [importlib] only brings in the contents of the type library.
Note my comment below :
If the IDL file which you wish to import contains the definition of some entity which is defined OUTSIDE the library statement, e.g. :
MyLibrary.IDL :
[
object,
uuid(...),
dual,
helpstring("ISomeInterface Interface"),
pointer_default(unique)
]
interface ISomeInterface : IDispatch
{
[id(1), helpstring("method TestMethod01")] HRESULT TestMethod01();
};
[
uuid(...),
version(1.0),
helpstring("MyLibrary 1.0 Type Library")
]
library MYLIBRARYLib
{
...
...
...
};
Then ISomeInterface will be accessible via an import statement in your current IDL file :
import "MyLibrary.IDL";
However, if ISomeInterface was defined INSIDE the library statement, e.g. :
MyLibrary.IDL :
[
uuid(...),
version(1.0),
helpstring("MyLibrary 1.0 Type Library")
]
library MYLIBRARYLib
{
[
object,
uuid(...),
dual,
helpstring("ISomeInterface Interface"),
pointer_default(unique)
]
interface ISomeInterface : IDispatch
{
[id(1), helpstring("method TestMethod01")] HRESULT TestMethod01();
};
...
...
...
};
then ISomeInterface can only be accessed via importlib("MyLibrary.tlb").
|
|
|
|
|
Note also the following :
Any entities defined outside the "library" block will cause code to be created by the MIDL compiler that will be used to generate both the proxy stubs and header files for marshaling code.
However, such entities will not be automatically included in a type library generated from the IDL file.
However, if any such entities was referenced inside the "library" block, then it will be included in the type library.
|
|
|
|
|
It seems possible for Visual Basic apps to use MTA COM objects.
|
|
|
|
|
The extern "C" declaration is used to tell the C++ compiler not to mangle the symbol which is being declared.
When the C++ compiler encounters a function name like "DisplayCurrentThreadId()" which has not been declared as extern "C", it will emit a symbol for it which will look like the following :
?DisplayCurrentThreadId@@YAXXZ
The actual symbol produced depends on the compiler used (the above was produced by VC++ 6.0). This symbol will be used in the resulting OBJ file for linking purposes.
C++ has a variety of reasons for symbol name mangling, of course. But the reason for the mangling of function names (both class functions and global ones) is to enable function name overloading (i.e. using the same function name with different parameter types).
If extern "C" was used to declare the function, the symbol produced for it could be:
_DisplayCurrentThreadId
This depends on the compiler used. But the bottom line is that no function name overloading will be allowed (since the C language does not support this, hence extern "C").
|
|
|
|
|
i am glad that i can learn about the real functionality of using exern"C" which i used to use without truly understanding-- just use it like like other people do.
|
|
|
|
|
1. A Proxy/Stub DLL is always required under one of the following situations :
1.1 Your COM object resides in an EXE Server.
Further note the following :
1.1.1 This is where the use of marshalling is most natural.
1.1.2 In order for your client (a separate EXE application) to use your COM object, marshalling is required.
1.2 Your COM object resides in a DLL Server.
Further note the following :
1.2.1 A COM object will always be used by a thread in a client application.
1.2.2 A client thread which uses COM will always reside in an apartment.
1.2.3 A COM object will also always reside in an apartment.
1.2.3 If the apartment of a client thread which uses a COM object is not the same the apartment of the COM object, marshalling will be required.
To put things simply, where a COM object is accessed across threads (be it threads of a single process or threads across processes), marshalling may be involved.
2. Even when you are using OLE-automation-compatible types, marshalling will be involved.
2.1 In this case, the standard COM marshaller is used. However, note carefully :
2.1.1 That this is provided that your interface has been assigned the [dual] or the [oleautomation] attribute.
2.1.2 If not, your interface cannot be marshaled using the standard COM marshaler.
2.2 The standard COM marshaler is oleaut32.dll (the standard Proxy/Stub DLL for Ole Automation).
2.2 In this case, you do not have to build any Proxy/Stub DLL in order for your clients to use your interface.
3. If your interface uses non-OLE-automation-compatible types as parameters, or that it uses OLE-automation-compatible parameter types but that it is not marked with the [dual] or [oleautomation] attributes, you would definitely need a Proxy/Stub DLL.
3.1 Note that your Proxy/Stub DLL is meant to be used for interfaces and not implementations.
3.2 For example, if you have an interface IAnInterface, say. And you have two implementations of IAnInterface in two separate DLLs, the two implementations will use the same Proxy/Stub DLL.
3.3 Every interface that is ever defined in a Windows OS will have an entry in the registry (under the HKEY_CLASSES_ROOT\Interface Key). They are registered under their GUIDs.
3.4 You will notice that many of the interface entries have a "ProxyStubClsid32" subkey.
3.5 This subkey contains a GUID which identifies the Proxy/Stub DLL associated with this Interface.
4. If you use the MIDL compiler, the source codes for building a Proxy/Stub DLL for your interface can be generated for you.
4.1 The followig files, generated by the MIDL compiler, are the raw materials for your Proxy/Stub :
- *_i.c
- *_p.c
- dlldata.c
where * denotes the name of your COM project.
The *_i.c file contains the actual definitions of the IIDs and CLSIDs defined in your COM project IDL file.
The *_p.c file contains proxy/stub data specific to the interfaces defined in your IDL file.
The dlldata.c file contains macros and code that help to generate basic COM DLL requirements (e.g. DllCanUnloadNow(), DllGetClassObject(), etc).
4.2 Start Visual C++ and create a basic Win32 DLL (non-MFC and non-ATL) project.
4.3 Add the *_i.c, *_p.c and dlldata.c files into this project.
4.4 Create your own .DEF file which should contain the following definitions :
LIBRARY <YOUR MODULE NAME>
EXPORTS
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
GetProxyDllInfo
4.5 You will need to supply the following pre-processor definitions to your project :
- REGISTER_PROXY_DLL
- either _WIN32_WINNT=0x400
- or _WIN32_WINNT=0x500 (if any interfaces has async_uuid attribute)
The REGISTER_PROXY_DLL definition will ensure that two of the basic COM DLL required exported functions DllRegisterServer() and DllUnregisterServer() are generated within dlldata.c.
The "_WIN32_WINNT=0x400" or "_WIN32_WINNT=0x500" is required otherwise you will face several compilation errors.
If any interface has been attributed with "async_uuid" then you will also need to use the correct-versioned "rpcproxy.h" file. If you are not using the correct-versioned one, the compiler will complain of this. The latest MS SDK include directory usually will contain the latest version of "rpcproxy.h". To use this, set $(MSSDK)\include in your "Additional include directories" path (under project settings).
4.6 Your project will also need to link to rpcrt4.lib.
4.7 After building a successful Proxy/Stub DLL project, you must remember to register this DLL.
<div class="ForumMod">modified on Thursday, January 29, 2009 12:31 AM</div>
|
|
|
|
|
2007 May 3rd
-------------
More notes :
1. Note that it is the Proxy/Stub DLL which generates the appropriate information for a non-OLE-automation-compatible (i.e. custom) interface. This includes the GUID and name of the interface, the number of methods it exposes, etc.
2. When the Proxy/Stub DLL is registered, it officially writes these Interface information in the registry (inside the custom interface's entry under the HKEY_CLASSES_ROOT\Interface registry key). The DLL also registers the GUID of the Proxy/Stub DLL (i.e. itself) associated with each custom interface.
3. In order to enable the Proxy/Stub DLL to contain such information, the Interface as defined in the original IDL must be declared outside the "library" block.
4. The best practice is to define the interface outside the library block and then reference that interface from inside the library block, as shown in this example:
//file: AllKnown.idl
[
object, uuid(. . .), <other interface="" attributes="">
]
interface IKnown : IUnknown
{
import "unknwn.idl";
<declarations,>
};
[
<library attributes="">]
library KnownLibrary
{
//reference interface IKnown:
interface IKnown;
//or create a new class:
[
<coclass attributes="">
]
coclass KnowMore
{
interface IKnown;
};
};
[example above taken from MSDN]
5. Note that the original Type Library whose compile-time IDL-file being the one in which the custom interface was originally defined, would not be able to generate the information mentioned in point 1 above for the custom interface. This is because it has no knowledge of the GUID of the Proxy/Stub which will be associated with the custom interface.
6. Note also that for custom interfaces, the type library is not needed. In fact, type libraries are not relevant for them to be used by a client.
modified on Friday, June 20, 2008 6:01 AM
|
|
|
|
|
2008 June 20th
---------------
More Notes :
1. I noticed that if a proxy/stub DLL has been generated for an interface that is oleautomation compatible (i.e. dual or oleautomation attributes have been assigned to the interface), then the proxy/stub DLL will be used even if the Universal Marshaler (i.e. OLEAUT32.DLL) could have been used (assuming of course that the interface has been defined inside a Type Library and that the Type Library has been registered).
2. However, if that proxy/stub DLL is not registered, the Type Library will be used.
3. Note however, that re-registration and/or recompilation of the Type Library and COM Server code may be necessary to effect a switch around.
|
|
|
|
|
// Here is an example of using mem_fun1 together with bind1st()
// to call a member function of a class which has been instantiated.
// The basic objective is to be able to call the for_each() algorithm
// with the use of a member function of an object as the target function
// to be called on each item in the container.
#include <set>
#include <functional>
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class myClass
{
public :
// Note : parameter pString must not be a pointer
// nor a reference.
int DoSomethingWithString( std::string pString )
{
cout << pString.c_str() << endl;
return 0;
}
public:
void Go()
{
std::set<std::string> myStrings;
myStrings.insert("ABC");
myStrings.insert("DEF");
myStrings.insert("GHI");
std::for_each
(
myStrings.begin(),
myStrings.end(),
// Here is the challenging usage of bind1st and mem_fun1.
std::bind1st(std::mem_fun1(&myClass::DoSomethingWithString), this)
);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
myClass mc;
mc.Go();
return 0;
}
|
|
|
|
|
Another way to achieve the use of a member function in such a situation is to declare a class deriving from std::string :
class MyString : public std::string
{
public :
MyString()
{
}
MyString(const char* pstring) :
std::string(pstring)
{
}
~MyString()
{
}
void DoSomethingWithString()
{
std::cout << c_str() << std::endl;
}
};
You basically extend the std::string with a public member function named DoSomethingWithString().
Then in myClass::Go(), you use MyString instead of std::string :
void Go()
{
std::set<MyString> myStrings;
myStrings.insert("ABC");
myStrings.insert("DEF");
myStrings.insert("GHI");
std::for_each
(
myStrings.begin(),
myStrings.end(),
mem_fun_ref(&MyString::DoSomethingWithString)
);
}
Use mem_fun_ref() as the predicate for for_each(). Basically, MyString::DoSomethingWithString() wsill be called on each contained object in myStrings (which is a set of MyString objects).
|
|
|
|
|
It seems best to install CDT via the "Software Updates" facility of the eclipse IDE.
Use the following URL in a Site Bookmark in the update manager:
http://download.eclipse.org/tools/cdt/releases/eclipse3.1
To install CDT from the update site, in the Help menu select Software Updates and then Find and Install, Select Search for new features to install and click Next. Click New Remote Site to add an update with the URL provided above, and then expand the site node to reveal the available downloads.
|
|
|
|
|
Note
-----
When you build your project, you can choose a MinSize or MinDependency configuration. MinSize will generate a smaller component, since shared code will be used from Atl.dll. In this case, you must distribute Atl.dll with your component. MinDependency will generate a larger component, since all necessary code will be linked in with your component.
Note
-----
When building a Release version of a project, you can get the following link error:
LIBCMT.LIB(crt0.obj) : error LNK2001: unresolved external symbol _main
This error occurs if you are using CRT functions that require CRT startup code. The Release configurations define _ATL_MIN_CRT, which excludes CRT startup code from your EXE or DLL. To avoid this error, do one of the following:
Remove _ATL_MIN_CRT from the list of preprocessor defines to allow CRT startup code to be included. On the Project menu, click Settings. In the Settings For: drop-down list, choose Multiple Configurations. In the Select project configuration(s) to modify dialog box that appears, click the check boxes for all Release versions, and then click OK. On the C/C++ tab, choose the General category, then remove _ATL_MIN_CRT from the Preprocessor definitions edit box.
If possible, remove calls to CRT functions that require CRT startup code and use their Win32 equivalents. For example, use lstrcmp instead of strcmp. Known functions that require CRT startup code are some of the string and floating point functions.
|
|
|
|
|
Q : Why do I get a "LNK2001: unresolved external symbol _main" error or "LNK2001: unresolved external symbol _WinMain" when I try to build my application?
A : This usually happens when you create the wrong type of project for you application. In the first case, you chose "Win32 Application" when you should have selected "Win32 Console Application". On the second case, well, it's the other way.
There are two ways to fix it: (1) Create a new project of the correct type, and readd all your files too it, or (2) change the type of the current project. This can be easily accomplished. Select Project -> Settings from the menu, and go to the Link tab. There, in the edit control at the bottom, look for the /subsystem switch and change it to "/subsystem:console" or "/subsystem:windows" as appropriate.
|
|
|
|
|
Hi all,
does anybody knows if it is possible to have different behaviour of a function in template classes ?
I need to control the flow in differen cases.
I need something like this example (where I used a pseudo code format)
template <typename MYTYPE>class CMyClass{
MYTYPE var;
...
void fun(){
CString str;
//Flow contol !!
if(MYTYPE == int) str.Format("%d",var);
if(MYTYPE == float) str.Format("%f",var);
if(MYTYPE ???) str="Unable format conversion";
}
...
}
|
|
|
|
|
Hello _Russell_,
What you need is known as "explicit template specialization". Define each specialized version of "void fun()" as follows :
void CMyClass<int>::fun()
{
str.Format("%d", var);
}
void CMyClass<float>::fun()
{
str.Format("%f", var);
}
Best Regards,
Bio.
|
|
|
|
|
You also need to put template<> before explicit specializations.
--Mike--
|
|
|
|
|
Thanks friends,
It works.
But let me know if are possible other solutions, expecially if exist a way similar to the way that I used in the first message (if it exist then in some cases it can be a very fast way to write code!)
|
|
|
|
|
Yes, you can use a policy-based design as one way to solve this:
template <class T> struct format_string
{
LPCTSTR get_string() { assert(false); }
};
template<> struct format_string<int>
{
LPCTSTR get_string() { return _T("%d"); }
};
template<> struct format_string<float>
{
LPCTSTR get_string() { return _T("%f"); }
};
template<class T, class policy=format_string<T> >
class foo
{
public: void fun() { CString s = policy::get_string();}
};
--Mike--
|
|
|
|
|
Is there a way i can contact you, Lim? I can be reached at jubithn@nway.in
Regards
Jubith Nambradth
|
|
|
|
|
Operator new allocates memory from the heap, on which an object is constructed. Standard C++ also supports placement new operator, which constructs an object on a pre-allocated buffer. This is useful when building a memory pool, a garbage collector or simply when performance and exception safety are paramount (there's no danger of allocation failure since the memory has already been allocated, and constructing an object on a pre-allocated buffer takes less time):
void placement() {
char *buf = new char[1000]; //pre-allocated buffer
string *p = new (buf) string("hi"); //placement new
string *q = new string("hi"); //ordinary heap allocation
cout
|
|
|
|
|
Placement New/Delete
In C++, operators new/delete mostly replace the use of malloc() and free() in C. For example:
class A {
public:
A();
~A();
};
A* p = new A;
...
delete p;
allocates storage for an A object and arranges for its constructor to be called, later followed by invocation of the destructor and freeing of the storage. You can use the standard new/delete functions in the library, or define your own globally and/or on a per-class basis.
There's a variation on new/delete worth mentioning. It's possible to supply additional parameters to a new call, for example:
A* p = new (a, b) A;
where a and b are arbitrary expressions; this is known as "placement new". For example, suppose that you have an object instance of a specialized class named Alloc that you want to pass to the new operator, so that new can control allocation according to the state of this object (that is, a specialized storage allocator):
class Alloc {/* stuff */};
Alloc allocator;
...
class A {/* stuff */};
...
A* p = new (allocator) A;
If you do this, then you need to define your own new function, like this:
void* operator new(size_t s, Alloc& a)
{
// stuff
}
The first parameter is always of type "size_t" (typically unsigned int), and any additional parameters are then listed. In this example, the "a" instance of Alloc might be examined to determine what strategy to use to allocate space. A similar approach can be used for operator new[] used for arrays.
This feature has been around for a while. A relatively new feature that goes along with it is placement delete. If during object initialization as part of a placement new call, for example during constructor invocation on a class object instance, an exception is thrown, then a matching placement delete call is made, with the same arguments and values as to placement new. In the example above, a matching function would be:
void operator delete(void* p, Alloc& a)
{
// stuff
}
With new, the first parameter is always "size_t", and with delete, always "void*". So "matching" in this instance means all other parameters match. "a" would have the value as was passed to new earlier.
Here's a simple example:
int flag = 0;
typedef unsigned int size_t;
void operator delete(void* p, int i)
{
flag = 1;
}
void* operator new(size_t s, int i)
{
return new char[s];
}
class A {
public:
A() {throw -37;}
};
int main()
{
try {
A* p = new (1234) A;
}
catch (int i) {
}
if (flag == 0)
return 1;
else
return 0;
}
Placement delete may not be in your local C++ compiler as yet. In compilers without this feature, memory will leak. Note also that you can't call overloaded operator delete directly via the operator syntax; you'd have to code it as a regular function call.
[from web page : http://www.glenmccl.com/tip_025.htm[^]]
|
|
|
|
|