|
You do not need to rerun the class wizard to change the threading model from apartment to free threaded. I believe you can find this under registry resource for your project (just change where it says 'apartment' or 'both' to 'free'), after you make the change be sure to re-register the interface. As far as creating a singleton object is concerned, there is an ATL macro 'DECLARE_CLASSFACTORY_SINGLETON' which should do the trick for you, the macro basically specifies that the class CComClassFactorySingleton will be the object which is queried upon every call to CreateInstance allowing a single instance to be passed for each call.
The only caveat is that you must make sure that the CurrentStateInterface is thread safe. This means protecting access to any shared objects or data (by shared, I mean objects that may be modified across threads). If everything is strictly read only, I don't think you have anything to worry about, but if you are modifying data, you must make sure you wrap these parts of the program in critical sections to correctly synchronize access these to objects.
Unfortunately, I don't have any code which I am able to share with you implementing singleton objects. There should be many examples however in MSDN. Do a search on the DECLARE_CLASSFACTORY_SINGLETON macro and see what you come up with.
Cheers!
|
|
|
|
|
I have a small & simple COM Server DLL (in straight C++). At the moment I'm not using ATL or MFC. It's all "pure" C++.
Now I want to add a dialog, and that dialog is going to use a List control within. The easiest (and perhaps only?) way to do this is via MFC.
What's the *minimal* amount of work I'd have to do in order to get enough MFC stuffed in to use CDialog and basic Common Control stuff in my DLL?
One obvious option is to have another .DLL using MFC and have my COM server call into that, which I'll do if that's much easier. But maybe there's something better.
Suggestions?
|
|
|
|
|
You can also use ATL windowing classes to do just this. Checkout CDialogImpl<> classes for dialogbox support. Similarly Listboxes and other common controls are also supported by ATL common control wrappers. You might even find ATL windowing a tad easier than rigging MFC support to your COM project at this stage.
|
|
|
|
|
I really should knuckle down and learn the ATL basics. Maybe this is the excuse I need. How easy is it to retrofit minimal ATL support?
I'm kinda "old school" in that I dislike over-use of "libraries" that hide too much stuff from me. But I'm willing to trade that off for *some* convenience. If you were around me in the early days of MFC when half my time was spent fixing *their* bugs, usually in non-overridable MFC code, you'd understand.
|
|
|
|
|
|
I'm trying to write a function which returns a pointer to itself from my ATL C++ code to a VB application. My ATL object uses dispinterfaces to be compatible with VB. In my IDL, I declare the my function:
[id(1)] HRESULT GetComponent ([out, retval] IDispatch *pRetval);
I implement the function OK and return a pointer to IDispatch that I've obtained with QueryInterface. Oh, this interface is part of a coclass alled "MyControl". So GetComponent basically returns QueryInterface on "this". (And it works, too )
I declare the interface as "oleautomation". Now using the Visual Basic object browser, I can see my GetComponent method and it's returning an "object". Now, I can set it OK if I set it as an object:
Dim Test as Object
Set Test = oControl.GetComponent ' oControl is type MyControl
However, if I declare "Test" as type "MyControl", I get a type mismatch:
Dim Test as MyControl
set Test = oControl.GetComponent ' Causes a type mismatch
Help! I just cannot get this to work. Is there something i must mark the IDL with, or is this a Visual Basic issue?
Thanks in advance
Jon
|
|
|
|
|
You should specify pointer to interface pointer to return your object.
[id(1)] HRESULT GetComponent ([out, retval] IDispatch* *pRetval);
Sure to call AddRef() on it before the function's exit.
With best wishes,
Vita
|
|
|
|
|
hello sir ..
I require some help from the programmers. I want to have a program which could scan all the HDD present in the network with thier Volume Serial Number ....since Volume Serial Number is the only way to uniquely identify a HDD
and store the output to a Microsoft Access Database file.
At a particular amount of time it should tell that a particular HDD with this volume serial number is connected or not?
somone told me that this can be done with WMI and the output can be taken in access file...
plzz help me
--thnx
waiting for a quick reply...
|
|
|
|
|
Hi,
I want to subscribe to events from an in process ATL COM object. This object is instantiated in a seperate process. I know the code I'm using to generate the events is working properly, but I don't know how to 'grab' the correct instance of the COM component so I can receive these events. If I call CoCreateInstance, I'm creating a new seperate instance of the same object. How do I retrieve the running instance of an inprocess COM object ? Is this possible ? Is there some example code I can look at ?
Mark
|
|
|
|
|
I know only one way how to solve your problem here. You have a choise to create an out-of-process COM object and make just a single instance of it in the memory. That means by any calling of CoCreateInstance(..) you connect just to that single instance of your COM object.
For creation of a single instance in Visual C++ ATL you can use a macro:
DECLARE_CLASSFACTORY_SINGLETON( CMyCass )
Jawid
|
|
|
|
|
Your in-proc object must register yourself in ROT by RegisterActiveObject(). Then any client can retrieve it by GetActiveObject() and subscribe to events.
With best wishes,
Vita
|
|
|
|
|
i have created two com classes in ATL A and B.The class B
also fires event . if i declare an object of class B in
visual basic using WithEvents keyword and then create its
object using NEW keyword,evenrything runs fine and i can receive events in vb client.
But the problem is ,i dont want to create the Class B object in Visual basic ,instead i have method in CLass A
which creates the object and returns the interface to
vb client,now when Object B fires event the com server crashes.
can anybody help me how to solve this problem.
|
|
|
|
|
There is no real problem.
Dim WithEvents bb As B
...
Set bb = New B
or
Set bb = a.CreateBObject
are equal to receive the B events.
With best wishes,
Vita
|
|
|
|
|
I am craeted a ComAddin for Excel using MFC;And I created a ExcelAddin(Save work book as a addin).
in the ComAddin I wont to access ExcelAddin's sheet.
How to access objects of ExcelAddin?
|
|
|
|
|
Hi, all
Some problems about ATL Com:
1.I have create two ATL Object: CStudent and CTeacher .
The simple source code listed as follow: (some code auto generated by ATL have been skiped)
class CStudent
{
private:
long m_age;
public:
CStudent():m_age(10)
{
}
//...other code auto generated by ATL
};
class CTeacher
{
private:
IStudent* m_aStudent;
public:
CTeacher()
{
//create an instance of the com
CoCreateInstance(CLSID_Student,NULL,CLSCTX_ALL,IID_IStudent, (void**)&m_aStudent);
}
//...other code auto generated by ATL
}
2.Then I add a "IStudent * OneStudent" property for ITeacher ,to access the m_aStudent.
The implemention of the property are listed as below:
STDMETHODIMP CTeacher::get_OneStudent(IStudent *pVal)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
// TODO: Add your implementation code here
*pVal = * m_aStudent;
return S_OK;
}
STDMETHODIMP CTeacher::put_OneStudent(IStudent *newVal)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
// TODO: Add your implementation code here
*m_aStudent = *newVal ;
return S_OK;
}
3.Now I type some VB code to test the com ,but some compiler errors occurrs.
VB Code:
Dim s As Student
Dim t As New Teacher
s = t.OneStudent
the last sentence "s = t.OneStudent" have compiler errors.
Errors:function or interface marked as restricted ,or the function use an Automation type not supported in Visual Basic
I guess the errors caused by the type dismatch between IStudnet and CStudent.But I did not know how to resolve it .
So who can tell me how to return the m_aStudent that can be supproted in vb??
thx.
Regards.
|
|
|
|
|
STDMETHODIMP CTeacher::get_OneStudent(IStudent* *pVal)<br />
{<br />
AFX_MANAGE_STATE(AfxGetStaticModuleState())<br />
*pVal = m_aStudent;<br />
if( m_aStudent != NULL )<br />
m_aStudent->AddRef();<br />
return S_OK;<br />
}<br />
<br />
STDMETHODIMP CTeacher::put_OneStudent(IStudent *newVal)<br />
{<br />
AFX_MANAGE_STATE(AfxGetStaticModuleState())<br />
if( m_aStudent != NULL )<br />
m_aStudent->Release();<br />
m_aStudent = newVal ;<br />
if( m_aStudent != NULL )<br />
m_aStudent->AddRef();<br />
return S_OK;<br />
}<br />
In VB you should use the "Set" operator to assign one object to another.
Set s = t.OneStudent<br />
With best wishes,
Vita
|
|
|
|
|
I have a COM interface and would like the CLSID for the underlying implementing object. The interface I have decends from IDispatch, and I have played with ITypeInfo. I am able to get the IID of the interface, but not the CLSID of the object. Is there an easy way to do this?
Thanks,
cagey
|
|
|
|
|
In order to get CLSID of running COM instance that object must have at least IPersist to be implemented.
--or--
To read CLSID from TypeLib (If you TypeLib has more then one coclass and some of those coclasses have implemented the same interface you can not say which coclass is instantiated):
#include <stdio.h>
#include <windows.h>
#include "comdef.h"
#include "atlbase.h"
void main()
{
CoInitialize(0);
{
CComPtr<IDispatch> p;
HRESULT hr;
hr = p.CoCreateInstance(L"TestObj.Test");
if(S_OK == hr)
{
::ITypeInfo *pti;
::ITypeLib *ptl;
UINT ui;
hr = p->GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT,&pti);
if(S_OK == hr)
{
hr = pti->GetContainingTypeLib( &ptl, &ui);
pti->Release();
if(S_OK == hr)
{
ui = ptl->GetTypeInfoCount();
for(UINT i = 0; i < ui; ++i)
{
hr = ptl->GetTypeInfo(i, &pti);
if(S_OK == hr)
{
::TYPEATTR *patr = 0;
hr = pti->GetTypeAttr( &patr);
if(patr->typekind == TKIND_COCLASS)
{
printf("OK - TKIND_COCLASS\n");
OLECHAR *wsz;
hr = ::StringFromCLSID(patr->guid, &wsz);
if(S_OK == hr)
{
printf("CLSID = %s\n",(char*) _bstr_t(wsz));
::CoTaskMemFree(wsz);
}
}
pti->Release();
}
}
ptl->Release();
}
}
}
}
CoUninitialize();
}
soptest
|
|
|
|
|
soptest's code should be working in most cases, but first check if the object supports IPersist, IProvideClassInfo or IProvideClassInfo2. You can then obtain the class ID in a very simple way through:
IPersist::GetClassID()
IProvideClassInfo2::GetGUID()
gertjan
|
|
|
|
|
I have written a C++ application that uses the COM+ event system. It consists of a publisher that creates log strings and
a subscriber client that creates a transient event subscription to get notifications every time a log string is sent. Everything
works fine when I run the publisher and subscriber on the same host, but if I try to subscribe from another host it fails.
The setup code looks like this:
BOOL RegisterTransientSubscription(LPCOLESTR SubscriptionName,
LPCOLESTR pszEventID,
IUnknown *pUnknown,
LPOLESTR* ppszSubscriptionID)
{
ICOMAdminCatalog* pac;
HRESULT hr = E_FAIL;
// Get an ICOMAdminCatalog interface pointer.
hr = ::CoCreateInstance (CLSID_COMAdminCatalog, NULL,
CLSCTX_SERVER,
IID_ICOMAdminCatalog,
(void**) &pac);
if (SUCCEEDED (hr))
{
ICatalogCollection* pcc = NULL;
BSTR bstr = ::SysAllocString(OLESTR \
("TransientSubscriptions"));
// host name edit empty <=> local publisher,
// otherwise remote host...
if (m_sHostName.IsEmpty())
{
// Get an ICatalogCollection pointer for the
// TransientSubscriptions collection (local).
hr = pac->GetCollection(bstr, (IDispatch**)&pcc);
::SysFreeString (bstr);
} else {
ICatalogCollection* tmp;
hr = pac->Connect(m_sHostName.AllocSysString(),
(IDispatch**)&tmp);
if (SUCCEEDED(hr))
{
VARIANT v;
VariantInit(&v);
hr = tmp->get_Name(&v);
hr = tmp->GetCollection(bstr, v,
(IDispatch**)&pcc);
tmp->Release();
}
}
if (SUCCEEDED (hr))
{
// Add an item to the TransientSubscriptions
// collection.
ICatalogObject* pco;
hr = pcc->Add((IDispatch**) &pco);
if (SUCCEEDED (hr))
{
// Register a transient subscription.
hr = SetStringProperty(pco, OLESTR("Name"),
pszSubscriptionName);
hr = SetStringProperty(pco,
OLESTR("EventCLSID"),
pszEventID);
hr = SetBoolProperty(pco, OLESTR("Enabled"),
TRUE);
hr = SetIUnknownProperty(pco, OLESTR\
("SubscriberInterface"),
pUnknown);
// Copy the subscription ID to the address
// specified by the caller.
VARIANT var;
::VariantInit (&var);
bstr = ::SysAllocString (OLESTR ("ID"));
pco->get_Value (bstr, &var);
::SysFreeString (bstr);
int nSize = (::SysStringLen(var.bstrVal) + 1) *
sizeof (OLECHAR);
BYTE* pBuffer = new BYTE[nSize];
::CopyMemory (pBuffer, var.bstrVal, nSize);
*ppszSubscriptionID = (LPOLESTR) pBuffer;
::VariantClear (&var);
pco->Release();
}
// Write the changes to the catalog.
long lResult;
hr = pcc->SaveChanges(&lResult);
pcc->Release();
}
pac->Release();
}
return (SUCCEEDED(hr)) ? TRUE : FALSE;
}
Any help would be much appreciated (2 weeks of debugging/testing/experimenting and I still don´t know what's wrong).
Regards,
Stefan
|
|
|
|
|
Hi everybody,
I've implemented QueryStatus of the IOleCommandTarget interface. It looks like this:
interface IOleCommandTarget : IUnknown
{
[helpstring("method Exec")]
HRESULT Exec(
[in] const GUID *pguidCmdGroup,
[in] DWORD nCmdID, [in] DWORD nCmdExecOpt,
[in] VARIANTARG *pvaIn,
[in,out] VARIANTARG *pvaOut);
[helpstring("method QueryStatus")]
HRESULT QueryStatus(
[in] const GUID *pguidCmdGroup,
[in] ULONG cCmds,
[in,out] OLECMD *prgCmds,
[in,out] OLECMDTEXT *pCmdText);
};
But, when I try to compile the idl file I receive this error;
Creating Type Library...
Microsoft (R) MIDL Compiler Version 5.01.0164
Copyright (c) Microsoft Corp 1991-1997. All rights reserved.
Processing E:\development\COM experiments\ProxyObj\ProxyObj.idl
ProxyObj.idl
Processing D:\Program Files\Microsoft Visual Studio\VC98\INCLUDE\oaidl.idl
oaidl.idl
Processing D:\Program Files\Microsoft Visual Studio\VC98\INCLUDE\objidl.idl
objidl.idl
Processing D:\Program Files\Microsoft Visual Studio\VC98\INCLUDE\unknwn.idl
unknwn.idl
Processing D:\Program Files\Microsoft Visual Studio\VC98\INCLUDE\wtypes.idl
wtypes.idl
Processing D:\Program Files\Microsoft Visual Studio\VC98\INCLUDE\ocidl.idl
ocidl.idl
Processing D:\Program Files\Microsoft Visual Studio\VC98\INCLUDE\oleidl.idl
oleidl.idl
Processing D:\Program Files\Microsoft Visual Studio\VC98\INCLUDE\servprov.idl
servprov.idl
Processing D:\Program Files\Microsoft Visual Studio\VC98\INCLUDE\urlmon.idl
urlmon.idl
Processing D:\Program Files\Microsoft Visual Studio\VC98\INCLUDE\msxml.idl
msxml.idl
E:\development\COM experiments\ProxyObj\ProxyObj.idl(59) : error MIDL2025 : syntax error : expecting a type specification near "OLECMD"
E:\development\COM experiments\ProxyObj\ProxyObj.idl(59) : error MIDL2026 : cannot recover from earlier syntax errors; aborting compilation
Error executing midl.exe.
ProxyObj.tlb - 2 error(s), 0 warning(s)
Any idea why? Should I include something special?
Thx,
/Tommy
|
|
|
|
|
In IDL file:
import "oaidl.idl";
import "ocidl.idl";
import "docobj.idl";
With best wishes,
Vita
|
|
|
|
|
I have a C++ DLL that I created with a whole bunch of typedefs for structs and enums (as well as some exportable functions and classes). The DLL's work fine when being called by a C++ project. However, we would like to add support for Visual Basic so that it can use the user defined types and enums. I looked through MSDN and found an article that states if you want to pass UDT's from VB to a C++ DLL, you have to create a type library. Having never used COM before (let alone typelibs), how do I go about defining these items to export? I wold prefer to not have to rewrite the code to create a COM interface.
Any help would be greatly appreciated.
Brigg Thorp
Software Engineer
Timex Corporation
|
|
|
|
|
import "oaidl.idl";
import "ocidl.idl";
[
uuid(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX), // GUID of your Type Library. Use GUIDGEN.EXE from MS Common\Tools
version(n.m), // Version of your Type Library, e.g. 1.0
helpstring("XXXXXXXX") // Description of your Type Library
]
library XXXXLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
typedef [
uuid(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX),
version(n.m),
helpstring("XXXXXXXX")
]
enum tagXXXX
{
[helpstring("XXXXXXXX")]
XXXX = YYYY,
} XXXX;
typedef [
uuid(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX),
version(n.m),
helpstring("XXXXXXXX")
]
struct tagXXXX
{
} XXXX;
};
It's a template. Rename the XXXX placeholder with your Names and Values.
You can include this IDL-file into your project and create the TLB file. This TLB file can included into DLL (or EXE) as the resource, named "TYPELIB".
This TLB file (both alone or included into other module) must be registered with REGTLIB.EXE or VB itself if you will add this TLB into project's References (Browse button).
With best wishes,
Vita
|
|
|
|
|
Getting value from stuff you don't own is a compelling
idea. Just think, someone else has created something
that has value, and has made it available to you. You
can now leverage its value in ways that makes all
parties richer. That's the promise of web services.
You need to know about web services. The advent of
standards-based web services marks a new era of
system development. First mainframe, then client-server,
the Web, now web services makes it possible to leverage
every legacy system of the past and do so much more
with your information assets.
Architag Press, a division of Architag International
Corporation, announces the publication of Web Services
Implementation Guide, Volume 1: Getting Started, by
Brian E. Travis and Mae Ozkan.
Sample chapters of the book is available at
http://www.architag.com/press/wsig.
This book will show you what a web service is, and
how you can align your internal systems and external
trading partner interactions to take advantage of this
new concept in system integration.
You will learn about the "Three Steps to Web Services":
* Automate internal systems
* Determine integration points
* Expose integration points as web services
This book is for systems architects, developers,
and I.T. decision makers.
Highlights in this book:
* Written in a light, entertaining style.
* Emphasis on architectural design for web services.
* A tutorial on the state of web services standards.
* Plenty of real-life examples of web service use.
* Tutorials on the key technologies: XML, SOAP,
WSDL and UDDI.
* Code samples of key XML-based web services
technologies and extensions.
* Companion Web site with all code samples and
late-breaking information.
----
Download sample chapters of Web Services Implementation
Guide at http://www.architag.com/press/wsig/.
Stanford Powers, Publisher Architag International Corp
Phone: 866-898-0001 Outside US: +1-303-426-3126
Email: spowers@architag.com Fax: 720-294-1396
|
|
|
|
|