certain use of the bitwise operator unclear - c++-cli

why is the bitwise operator before variable name when declaring this
Ping ^pingSender = gcnew Ping;
Thanks

You are talking about this code??
Ping ^ pingSender = gcnew Ping;
// When the PingCompleted event is raised,
// the PingCompletedCallback method is called.
pingSender->PingCompleted += gcnew PingCompletedEventHandler( PingCompletedCallback );
Here this implies instance of ping class will be created from System.Net.NetworkInformation::Ping. Simply, this is not XOR operation but syntax of declaring object of managed type in microsoft implementation of C++ for .NET.

In this context, ^ is not the bitwise XOR; it declares pingSender to be a reference to the managed type (a type native to .NET) Ping.
I assume you are familiar with the basics of C# and regular, non-managed C++.
This line of code equals
Ping pingSender = new Ping();
in C#, and in case Ping was a non-managed C++ class,
Ping* pingSender = new Ping;
in C++. As you can see, ^ has another meaning when used in a declaration, just as * does for unmanaged types in C/C++.

Related

a pointer-to-memeber is not valid for a managed class

I have a Windows Form in Visual Studio C++. (CLR)
In the header file, I declare void createThread()
private:
void createThread() {
char buffer[1024];
ZeroMemory(buffer, sizeof(buffer));
while (true) {
recv(connection, buffer, sizeof(buffer), 0);
main.displayMessage(gcnew System::String(buffer));
}
ExitThread(0);
}
Now, I want to call function createThread
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)createThread, NULL, NULL, NULL)
After that I get this error:
a pointe-to-member is not valid for a managed class
I tried user thread library but not support. How can I fix??
It appears that this function is defined in a managed class. You need to use the managed thread object, not unmanaged CreateThread.
This error exists for two reasons: First, it's a instance method, not a static method, so it would need to be called with an instance of this type, which there's no way to pass to CreateThread. Second, it's a managed object, and its methods do not trivially convert to C-style raw function pointers.
Finally, a note about the language: C++/CLI is meant to act as a way to interface managed code (e.g., C#) with unmanaged C++. It's not intended as a primary development language. If you don't need to link managed and unmanaged code, you may want to consider switching to either C# or C++ for your application.

How to pass a struct parameter using TCOM in Tcl

I've inherited a piece of custom test equipment with a control library built in a COM object, and I'm trying to connect it to our Tcl test script library. I can connect to the DLL using TCOM, and do some simple control operations with single int parameters. However, certain features are controlled by passing in a C/C++ struct that contains the control blocks, and attempting to use them in TCOM is giving me an error 0x80020005 {Type mismatch.}. The struct is defined in the .idl file, so it's available to TCOM to use.
The simplest example is a particular call as follows:
C++ .idl file:
struct SourceScaleRange
{
float MinVoltage;
float MaxVoltage;
};
interface IAnalogIn : IDispatch{
...
[id(4), helpstring("method GetAdcScaleRange")] HRESULT GetAdcScaleRange(
[out] struct SourceScaleRange *scaleRange);
...
}
Tcl wrapper:
::tcom::import [file join $::libDir "PulseMeas.tlb"] ::char
set ::characterizer(AnalogIn) [::char::AnalogIn]
set scaleRange ""
set response [$::characterizer(AnalogIn) GetAdcScaleRange scaleRange]
Resulting error:
0x80020005 {Type mismatch.}
while executing
"$::characterizer(AnalogIn) GetAdcScaleRange scaleRange"
(procedure "charGetAdcScaleRange" line 4)
When I dump TCOM's methods, it knows of the name of the struct, at least, but it seems to have dropped the struct keyword. Some introspection code
set ifhandle [::tcom::info interface $::characterizer(AnalogIn)]
puts "methods: [$ifhandle methods]"
returns
methods: ... {4 VOID GetAdcScaleRange {{out {SourceScaleRange *} scaleRange}}} ...
I don't know if this is meaningful or not.
At this point, I'd be happy to get any ideas on where to look next. Is this a known TCOM limitation (undocumented, but known)? Is there a way to pre-process the parameter into an appropriate format using tcom? Do I need to force it into a correctly sized block of memory via binary format by manual construction? Do I need to take the DLL back to the original developer and have him pull out all the struct parameters? (Not likely to happen, in this reality.) Any input is good input.

Representing IUnknown In Managed C++

I building Wrapper in C++/CLI for C Static library to be used in .NET application through C#
I have function like this in C
long My_COM_Interface( PVOID hDevice,IUnknown **pUnknown);
How to declare IUnknown ** in C++/CLI
for first argument I am using IntPtr but Not able to find out the Replacement for IUknown.
I have another COM Data type GUID in another function this is also an issue for me.
Please Help me find the relacement for data type IUnknown and GUID.
There is no replacement.
C++/CLI understands native types just fine. Include the right header files, and you can use IUnknown* like always.
I'd refer to the APIs, e.g.
public static IntPtr GetIUnknownForObject(Object o);
This API can simply be used from C++/CLR and suggests you should use IntPtr^
try using parameter like;
ref object pUnknown
and use it like
MyObject o = pUnknown as MyObject

ComBSTR assignment

I'm confused about COM string assignments. Which of the following string assignment is correct. Why?
CComBSTR str;
.
.
Obj->str = L"" //Option1
OR should it be
Obj->str = CComBSTR(L"") //Option2
What is the reason
A real BSTR is:
temporarily allocated from the COM heap (via SysAllocString() and family)
a data structure in which the string data is preceded by its length, stored in a 32-bit value.
passed as a pointer to the fifth byte of that data structure, where the string data resides.
See the documentation:
MSDN: BSTR
Most functions which accept a BSTR will not crash when passed a BSTR created the simple assignment. This leads to confusion as people observe what seems to be working code from which they infer that a BSTR can be initialized just like any WCHAR *. That inference is incorrect.
Only real BSTRs can be passed to OLE Automation interfaces.
By using the CComBSTR() constructor, which calls SysAllocString(), your code will create a real BSTR. The CComBSTR() destructor will take care of returning the allocated storage to the system via SysFreeString().
If you pass the CComBSTR() to an API which takes ownership, be sure to call the .Detach() method to ensure the BSTR is not freed. BSTRs are not reference counted (unlike COM objects, which are), and therefore an attempt to free a BSTR more than once will crash.
If you use str = CComBSTR(L"") you use the constructor:
CComBSTR( LPCSTR pSrc );
If you use str = L"" you use the assignment operator:
CComBSTR& operator =(LPCSTR pSrc);
They both would initialize the CComBSTR object correctly.
Personally, I'd prefer option 1, because that doesn't require constructing a new CComBSTR object. (Whether their code does so behind the scenes is a different story, of course.)
Option 1 is preferred because it only does one allocation for the string where as option 2 does 2 (not withstanding the creation of a new temporary object for no particular reason). Unlike the bstr_t type in VC++ the ATL one does not do referenced counted strings so it will copy the entire string across.

How to create a global handle in C++-CLI

I am trying to use a C# class in a C++-CLI project, but Visual Studio will only let me declare a handle (^) to a C# object in a local scope, just inside a function. The only way I got it working was declaring a global pointer to a handle:
SUTAdapter::Form1^ *ptForm1;
But if then I create an object inside a function and give its address to the global pointer:
SUTAdapter::Form1^ form1;
form1 = gcnew SUTAdapter::Form1();
ptForm1 = &form1;
(*ptForm1)->incCounter(0);
When the function exits and I try to use the incCounter function inside some other C++-CLI function, the object seems gone (debugger says this == null). Is there a way to have a global handle of a C# code in C++-CLI? I guess global handles are forbidden for some reason I don't understand but I am out of ideas and I need this done. Thank you.
edit:
*ptForm1 = gcnew SUTAdapter::Form1();
Gives a null reference exception. Why?
This restriction seems consistent with the other CLR-based languages. C# has no concept of a static, function-scoped variable for example. The lack of such functionality in C++/CLI suggests that is the way the CLR works - static objects must be defined at the class scope.
The CLR is object based, so this is just a case of that object-oriented nature influencing the design of languages that run on top of it.
From an OO view point, I like the C# way better anyway.
Ok thanks for your answers but I finally solved it, I found it googling:
http://bytes.com/groups/net-vc/473036-how-define-global-com-object-vc-8-a
It seems that VS doesn't let global handles or static handles inside functions. I am puzzled about this because sometimes it is necessary to access managed objects globally.
The solution is to declare a "GlobalObjects" class with static handles inside it:
ref class GlobalObjects
{
public:
static SUTAdapter::Form1^ hndForm1;
};
This way I can access the C# form/class globally. The error code of the previoous error is C3145, I am still wondering why does not VS allow the declaration of global handles.
Will Visual Studio let you declare a static handle to a C# object in a local scope?
SUTAdapter::Form1^ theForm() {
static SUTAdapter::Form1^ form1 = gcnew SUTAdapter::Form1();
return form1;
}
*ptForm1 = gcnew SUTAdapter::Form1();
Gives a null reference exception because you are dereferncing a null pointer - it is just like a pointer to any other type in that regard.
I think - and that's without testing it - that the problem you're having is because you're storing a pointer to a local handle, which might confuse the garbage collector a little due to the fact that you're taking a pointer to an automatic object.
Have you tried to replace the above assignment with
*ptForm1 = gcnew SUTAdapter::Form1();
instead of the detour via the local object reference?