Hello all I have a project where I from C# code need to use a COM object and consume events. My COM object can send events by the use of Connectable Objects. In the good old days when C++ and COM were used, I used the IConnectionPoint and Advice. But, is there in .NET a way to consume COM events? I guess it will be in the System.Runtime.InteropServices.
Per Nilsson
Posts
-
C# and COM Events -
SQL Server 2008 R2: Errrors when sending ISO 8601 timestamp values as parameters to a parametrized insert statementI have problem inserting datetime values into my SQL Server 2008 R2. The server is capable of handling ISO 8601 format, but If I send them as parameters, the SQL Server/OLE DB provicer, seems to be less tolerant on the timestamp string format. I use OLE DB from C++ and would like to make my insert statement parametrized
INSERT INTO BATCH VALUES (?, ?, ?, ?....
When I specify timestamp values on the ISO8600 format, "2010-10-23T19:41:56.002+02:00", I get errors. When enter the same timestamp format directly in the statement, I don't get errors
INSERT INTO BATCH VALUES ('2010-10-23T19:41:56.002+02:00', ?, ?, ?....
I have tried two different OLE DB providers. "Microsoft SQL Server Native Client 10.0" and "Microsoft OLE DB Provider for SQL Server" They both behave slightly differently. When sending the timestamp values as part of the SQL INSET, both providers accepts the following formats
2010-10-23 19:41:58.000
2010-10-23T19:41:57.001
2010-10-23 19:41:56.002+02:00
2010-10-23T19:41:55.003+02:00When sending timestamp as parameter:
2010-10-21 13:44:59.092 Is accepted by both
2010-10-21T13:44:57.092 Is rejected by Microsoft SQL Server Native Client 10.0 and accepted by the other
2010-10-23 19:41:56.002+02:00 Rejected by both providers
2010-10-23T19:41:55.003+02:00 Rejected by both providersThe both providers also report different errors Microsoft OLE DB Provider for SQL Server reports "Conversion failed when converting date and/or time from character string" which I may understand. The "Microsoft SQL Server Native Client 10.0" reports HRESULT=DB_S_ERRORSOCCURRED. I would be glad if someone could explain these differences, especially why I can send the timestamp stirng litterally in the sql but not as a parameter.
-
How to send NULL to a IUnknown** parameter when COM object is surrogate hostedThanks for a very interesting link. Though, I was not able to reproduce the behavior, even with the code in the article. Even if I put,
unique
orptr
as attribute to my parameter ([in, string, unique]
) I get the same error code. I can pass aIUnknow*
with 0 as value, both withunique
andref
(which should be impossible), but a wchar_t* cannot be passed, regardless of theunique
attribute or not. /Per -
How to send NULL to a IUnknown** parameter when COM object is surrogate hostedThanks for the response. To clarify a bit. The parameter is used to return a COM pointer. If the caller don't need the value, it sends NULL. So my implementation has the following construction
if (ptr != 0) {
*ptr = something;
*ptr->AddRef ();
}This i not uncommon in C++ programming, but for some resaon its problematic in COM.
-
How to send NULL to a IUnknown** parameter when COM object is surrogate hostedI'm developing a COM object in a dll. The object takes an IUnknown** parameter.
interface IPasser : IDispatch{
[id(1), helpstring("method Pass")]
HRESULT Pass([in]IUnknown* ptr);};When using it in-process I can send NULL as parameter, but when I instantiate the com object usign a surrogage usign CLSCTX_LOCAL_SERVER I get an error message 0x800706f4, "A null reference pointer was passed to the stub."
IPasserPtr obj;
IUnknown* ptr;hr = obj.CreateInstance (CLSID_Passer, 0, CLSCTX_LOCAL_SERVER);
hr = obj->raw_Pass (0); // Returns 0x800706f4
hr = obj->raw_Pass (&ptr); // OKThis is only a problem when I use double indirection, not when I use an ordinary IUnknown*. Can anyone tell me why this is not allowed and how to change the implementation to be able to send a NULL pointer. /Per
-
How to load xml file from resources using msxml?It should not be much of a problem. I do it like this in a project (With all error handling removed. It just clutters up the example.)
int CHookApp::LoadXML (int rsrc, MSXML2::IXMLDOMDocument2Ptr& xml, CString& errMsg) { HRSRC hXSLResourceInfoBlock; HGLOBAL hXSLResource; hXSLResourceInfoBlock = ::FindResource (m_hInstance, MAKEINTRESOURCE(rsrc), "XSL"); if (hXSLResourceInfoBlock) hXSLResource = LoadResource (m_hInstance, hXSLResourceInfoBlock); if (hXSLResourceInfoBlock == NULL || hXSLResource == NULL) return -1; try { _bstr_t xmlText ((char*)LockResource (hXSLResource)); if (xml->loadXML ( xmlText ) == VARIANT_FALSE) return -1; } catch (...) { return -1; } return 0; }
I wonder why my empty lines are removed from the <pre> block above. It remained in another reply of mine....... -- modified at 5:03 Wednesday 14th December, 2005 -
String vs. XML fileYou can load the tring into an XMLDocument object much like you load it from file.
HRESULT loadXML(BSTR bstrXML,VARIANT_BOOL * isSuccessful);
This migth be an Microsoft extension of the DOM model, but it exists in MSXML. Then it is possible to transform it using the transformNode method of the XMLDocument object.HRESULT transformNode(IXMLDOMNode *stylesheet, BSTR *xmlString);
/Per -
How to restrict client application to create COM objectAs I've been curious about the same thing, I took this as an exercise, and if you use ATL for your COM server, I have the solution for you. ATL includes an object map in its implementation file that includes entries for each class the server implements. The map is located in the COM servers implementation file (named .cpp) and looks like this
BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_Creatable, CCreatable) OBJECT_ENTRY(CLSID_IsNotCreatable, CIsNotCreatable) END_OBJECT_MAP()
Change the object entry to OBJECT_ENTRY_NON_CREATEABLE of your non, creatable class.
BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_Creatable, CCreatable) OBJECT_ENTRY_NON_CREATEABLE(CIsNotCreatable) END_OBJECT_MAP()
After this, the CIsNotCreatable coclass cannot be created by CoCreateInstance. (Take a look at the documentation of OBJECT_ENTRY_NON_CREATEABLE in MSDN). To let the creatable class create an instance of the non creatable and return a COM pointer ot it, you can do like this
STDMETHODIMP CCreatable::CreateNotCreatableObject(IIsNotCreatable **obj) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) HRESULT hr; // // CComObject template class is the root of all ATL COM objects // The CComObject implements the IUnknown defined methods. // // We set up a pointer to a COM object of class CIsNotCreatable //(that inherits from IIsNotCreatable) // CComObject* instanceOfNotCreatableClass; // // Then we can use the CreateInstance static method olf CComObject to // create an instance of the object. (Otherwise we could have used new) // hr = CComObject::CreateInstance(&instanceOfNotCreatableClass); if (SUCCEEDED (hr)) { // // As we will return an COM pointer from our method, we must remember // to call AddRef on it. // instanceOfNotCreatableClass->AddRef (); // // Assign the return value // *obj = instanceOfNotCreatableClass; } return hr; }
-
How to create COM objects in different processesWhen I create multiple out-of-process COM instances of same class from a com server, is it then, in some way, possible to let them run in different processes? -- modified at 4:29 Tuesday 13th December, 2005
-
MprConfigGetFriendlyName returnins "Access denied"Hi I am using the MprConfigGetFriendlyName function in a program of mine. It works well if I'm an administrtor on my machine, but when I switch to a restricted user, I get "Access denied" from the funciton. I can't find any info about rights anywhere on MSDN. Can anyone give me a hint of how to proceed.
-
How to get the current instance handleYes "The Win32 API GetModuleFileName() is what you need. If you pass NULL as the module handle parameter, the function returns the path of the module that created the process (in other words - the application's exe file)."
-
How to get the current instance handleNo This function returns the module name of the creating process, not the dll I am executing in. /Per
-
How to get the current instance handleI have searched for a way to get the instance handle of the module that my code is executing in. AfxGetInstanceHandle function available, but only when running as an MFC dll. GetModuleHadndle is available, but requires the path of the dllm which I don't have. I cannot inject code in DllMain to "remember" the instance handle because I don't have access to it. I have a solution that is quite extensive using "Process Helper", "PE Image Helper" APIs and are quite time consuming. I hope to find a better way of doing it. Probably there exist a way for it, but I haven't found it yet. Does anybody have a solution for it?
-
What exception is thrown that I catch with a catch(..)?I woul'd like to catch the exception, but I don't know what type it is. Can I figure that out in some way?
-
What exception is thrown that I catch with a catch(..)?Hi Does anyone know how I can find out what exception has actualy been thrown when I catch it with catch (...) block. /Per
-
ImpersonationHello I would like to call ImpersonateLoggedOnUser to gain some extra rights for a particular task in my application. For the call I need an impersonation token. To get this I tried the LogonUser function, but I don't have enough privileges. Probably it's the SE_TCB_NAME privilege. If I inspect the results from GetTokenInformation it is true that I don't have that priv and hence cannot enable it. Does anyone know how to get a proper impersonation token. I've tried to call CreateProcessWithLogonW to create a dummy process as a different users, and with that process handle I can call OpenProcessToken to get a token to send to ImpersonateLoggedOnUser. This gives the expected result, but it is a verry uggly work around.
-
Arrays!Well. When an array is declared, its content is undefined unless you give it an initial value. Initial values are assigned to an array by listing values withing {}. If your array is larger than your initialization list, the remaining elements will be assigned 0 by the compiler.
int a[4]; // Undefined value int b[4] = {1,2}; // Contains values 1, 2, 0, 0
/Per -
know how to attack parallel port in win2kNeither can I. Try this http://www.codeproject.com/csharp/csppleds.asp
-
know how to attack parallel port in win2kHi Theres a really good article on this matter here at CP.
I/O Ports Uncensored - 1 - Controlling LEDs (Light Emiting Diodes) with Parallel Port[^] -
template class ProblemHi The solution is pretty simple. In stead of ClassA> obj; use ClassA > obj; Yes, the only difference is a space. The reason for the error is that the compiler finds '>>' and believes it to be the >> operator instead of the end of the template lists. So if you put in a space, the first > will end the inner template list and the second the outer and the compiler is happy.