Colleagues,
Preamble. My question is more about best practices. I know one workaround. This is the first time I have to deal with interop in C#, at the same time I’ve written a fair amount of code in C and C++.
I need to invoke 2 times a function exposed by an unmanaged DLL. The function takes a pointer to a struct as an argument. 1st time I need to pass a null pointer. 2nd time I need to pass a pointer to an instance of the struct.
The function has 6 parameters, so below are simplified declarations that work for the purposes of this question. (I can post the specifics if anyone is interested.) Here’s the 1st variant of the declaration:
[DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool foo(ref NEEDED_STRUCT_TYPE sDataStruct);
I like it, because it's strongly typed for the NEEDED_STRUCT_TYPE. But to be able to pass a null pointer, I had to change the declaration to
[DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool foo(IntPtr sDataStruct);
Now I can pass IntPtr.Zero for null pointer, but the parameter is no longer strongly typed. In the given situation, is there a way to have both: strongly typed parameter and the ability to pass null pointer?
Any suggestion, insight or reference is really appreciated!
Cheers,
- Nick
It's not uncommon to use a wrapper method with the exact API you want to expose (strongly typed, etc.) and then to have that wrapper method call the DllImport method, which is private. In other words, there's no reason the raw method needs to force the managed API.
Related
Every time I write a signature that accepts a templated callable, I always wonder what the best type for the parameter is. Should it be a value type or a const reference type?
For example,
template <class Func>
void execute_func(Func func) {
/* ... */
}
// vs.
template <class Func>
void execute_func(const Func& func) {
/* ... */
}
Is there any situation where the callable is greater than 64bits (aka a pointer to func)? Maybe std::function behaves differently?
In general, I do not like passing callable objects by const reference, because it is not that flexible (e.g. it cannot be used on mutable lambdas). I suggest to pass them by value. If you check the stl algorithms implementation, (e.g. for std::for_each), all of the callable objects are passed by value as well.
Doing this, the users are still able to use std::ref(func) or std::cref(func) to avoid unnecessary copying of the callable object (using reference_wrapper), if desired.
Is there any situation where the callable is greater than 64bits
From my experience in working in CAD/CAE applications, a lot. Functors can easily hold data that is bigger than 64 bits. More than two ints, more than one double, more than one pointer, is all you need to exceed that limit in Visual Studio.
There is no best type. What if you have noncopyable functor? First template will not work as it will try to use deleted copy constructor. You have to move it but then you will loose (probably) ownership of the object. It all depends on intended use. And yes, std::function can be much bigger than size_t. If you bind member function, it already is 2 words (object pointer and function pointer). If you bind some arguments it may grow further. The same goes with lambda, every captured value is stored in lambda which is basically a functor in this case. Const reference will not work if your callable has non const operator. Neither of them will be perfect for all uses. Sometimes the best option is to provide a few different versions so you can handle all cases, SFINAE is your friend here.
Informs the provider that a directory enumeration is starting
`
PRJ_START_DIRECTORY_ENUMERATION_CB PrjStartDirectoryEnumerationCb;
HRESULT PrjStartDirectoryEnumerationCb(
const PRJ_CALLBACK_DATA *callbackData,
const GUID *enumerationId
)
{...}
`
I am confused how to use this function.
You're looking at a callback (a generic programming concept, not specific to Win32), which is usually a reference to a function that you have to write yourself. In order to have the C/C++ compiler check that you've defined your callback function correctly, and to simplify usage of such callbacks, a typedef is often used. The Win32 API often uses all caps to define types of callbacks. In this case, PRJ_START_DIRECTORY_ENUMERATION_CB is the type of the function pointer (a pointer to the callback function that you have to write), and it is defined in projectedfslib.h as:
typedef
_Function_class_(PRJ_START_DIRECTORY_ENUMERATION_CB)
HRESULT
(CALLBACK PRJ_START_DIRECTORY_ENUMERATION_CB)(
_In_ const PRJ_CALLBACK_DATA* callbackData,
_In_ const GUID* enumerationId
);
This definition has a lot of excess stuff in it that helps the Microsoft toolset validate various things related to the usage of this type of function pointer. When writing your own function that works for this type of callback, you don't necessarily have to repeat a lot of the things that are used in the typedef. The MSDN documentation for callbacks often shows an example of how you would write the method signature for your callback, and that example is usually simplified to strip off the excess stuff that the toolset needs, leaving the stuff the developer needs to define when writing their callback.
In this case, the example function is called PrjStartDirectoryEnumerationCb, but there is no function defined with that name. It's up to you to define a function that looks like what you see on MSDN. It doesn't have to have the same name -- you can name it whatever you like, and then you use your function's name anywhere the callback is needed.
HRESULT MyCallback(const PRJ_CALLBACK_DATA *callbackData, const GUID* enumerationId)
{
// implement your callback here
}
I currently have a memory leak in my project. To resolve the memory leak, I am trying to replace the pointers into std:: unique_ptr. The pointer to the heap is not from my project, but rather from a library called Xerces(an XML parsing library).
In this library, it can transcodes char * to XMLCh * in both ways.
So in real code, it comes like ..
XMLCh * xmlstr = XMLString::transcode("abc",...);
char * charstr = XMLString::transcode(xmlstr,...);
since both methods allocates heap area and returns the pointer for it, I should explicitly call
XMLString::release(xmlstr);
XMLString::release(charstr);
after using it to clean up. I want to write a custom deleter for two types (char * and XMLCh *) using std::unique_ptr.
The release method has a type of
XMLString::release(char **str);
XMLString::release(XMLCh **str);
It is using double pointer because it sets the pointer to null after release.
I thought to make the template accept reference pointers like this,
template<typename T>
void release(T *& ptr){
XMLString::release(ptr);
}
but just realized that it will be possible to
XMLCh * xmlstr = XMLString::transcode("abc",...);
auto uptr = unique_ptr<XMLCH, decltype(&release<T>)>(xmlstr)
do this, but not possible to
auto xmluptr = unique_ptr<XMLCH, decltype(&release<T>)>(XMLString::transcode("abc",...));
do something like this, because it is accepting a rvalue in the parameter but the argument is a reference pointer. Is it possible to instantiate both cases writing only one template function?
By the way, I am using c++11.
So if I understand correctly, your problem is that XMLString::release takes a pointer-to-point and it does not fit into the unique_ptr release function. Well, the correct solution is to wrap it like
template<typename T>
void release(T *ptr){
XMLString::release(&ptr);
}
The XMLString::release will only null-out the copy of the pointer inside the wrapper, but since the unique_ptr takes care of rendering itself unusable itself, you don't need that functionality of XMLString::release.
In either case, the type of the release wrapper does not affect how the unique_ptr is constructed, because the release wrapper will be called with the internal member of the unique_ptr as argument. So either unique_ptr accepts that argument, and both assignments will work, or unique_ptr won't accept it and neither will.
That said, the point of unique_ptr is that you wrap the pointer in it immediately when you get it. So don't store it in variable before.
I have C++/CLI class that defines a property:
public ref class AbstractOffer
{
public:
AbstractOffer();
property String^ Body;
};
In some function the AbstractOffer class is passed by const ref
foo(const AbstractOffer^ ao)
{
ao->Body;
}
When I call the property the method compiler gives the following error :-
error C2662: 'ivrworx::interop::AbstractOffer::Body::get' : cannot
convert 'this' pointer from 'const ivrworx::interop::AbstractOffer'
to 'ivrworx::interop::AbstractOffer %' 1> Conversion loses
qualifiers
It seems somehow connected to const. How can I call the Body property of the object if the object reference is passed by const?
The const qualifier is a problem in C++/CLI. It is only meaningful when it can be checked and that's not in general possible in .NET. It is of course not a problem when you only have one kind of compiler and that compiler follows strict language rules. Like C++. But .NET supports many languages, your method could be easily called from a Cobol.NET program for example. The odds of ever getting const-correctness added to the Cobol language are zero.
The compiler does compile code with const qualifiers and does make an effort to check when it can. Which is why you got the diagnostic. That can even work when the declaration exists in another assembly, as long as it was compiled with C++/CLI, the compiler emits modopt annotations in the metadata.
But there are limitations with that. Properties are one of them, you can't add the const qualifier to the getter, or a member function in general, you'll get slapped with C3842.
Best thing to do is to use C++/CLI for what it is good at, it is an interop language. And const qualifiers just don't work well in an interop scenario.
The only way I know to get round this is the cast away the const-ness. As long as you don't modify the object, it should be fine. (If you do modify it, I've no idea what the outcome will be).
i.e. change your function to be
void foo(const AbstractOffer^ ao)
{
const_cast<AbstractOffer^>(ao)->Body;
}
I have a COM interface with a following method definition (IDL notation):
SCODE GetText( [in, out] ULONG* pcwcBuffer,
[out, size_is(*pcwcBuffer)] WCHAR* awcBuffer );
Typelib marshaling is used for COM+, the type library is registered, other methods of the interface work allright when called through COM+, but not this method.
The server side copies an array of WCHARs into the awcBuffer and its length into pwcBuffer, no buffer overrun ever occurs.
static const wchar_t* Text = L"Sample";
STDMETHODIMP CImpl::GetText( ULONG* bufferLength, WCHAR* buffer )
{
const int length = wcslen( Text );
*bufferLength = length;
memcpy( buffer, Text, length * sizeof( WCHAR ) );
return S_OK;
}
When the client calls this method through COM+ the buffer contents gets lost. Specifically only the first wide char is preserved - if the server copies "Sample" wide character string, the client only receives "S" string. The return value on the client size is S_OK, the buffer length returned to the client is exactly the same as what the server copied.
I finally switched to BSTR to workaround this problem but it's really interesting why the whole valid looking construct doesn't work.
What's the possible reason of the described behaviour?
IIRC, the typelib marshaller ignores the size_is attribute -- thus, only 1 char is marshaled.
J. Passing is right. For the typelib marshaller to work, the COM interface must be OLE Automation compatible. The typelib marshaller is implemented in oleaut32.dll, so I guess there's a clue in the name.
[size_is] is perfectly valid IDL, and compiles into a valid typelib, but the typelib marshaler can only handle a subset of valid interfaces. That subset is usually referred to as OLE Automation. As an aside, VB6 clients can only speak OLE Automation, so they wouldn't be able to consume your interface either.
Try marking your interface with the [oleautomation] attribute in your IDL. It should give you a warning or error message that might point you to more information on the subject.
In "normal" COM, you could generate a proxy/stub DLL from your IDL to do the marshalling, but I'm afraid I don't remember whether COM+ would use your custom marshalling code even if you bothered to build it.
Update: in Juval Lowy's book "COM and .NET Component Services", I found this statement: "...configured components cannot use interfaces that require custom marshaling". So I guess that interface will never work in COM+. If you can, re-write to use a BSTR instead.
Couple of questions:
Why aren't you using BSTR?
Do you have the sources of the GetText function?
What is the size of the buffer returned by the function?