In my C# console application, I'm having an error for this structure:
The error message seems fairly clear - where were you expecting the type to come from? It looks like you're basically missing the declaration of the struct, which you can take from PInvoke.NET.
Basically, P/Invoke is a way of exposing native library calls to managed code, but for complex types, you need a managed representation of the type - and .NET doesn't come with a representation of CONSOLE_SCREEN_BUFFER_INFO, so you have to declare it yourself. PInvoke.NET contains a lot of these declarations, as well as the declarations for the functions that use them. (They're not always accurate, but in my experience they usually are.)
Related
I'm using Visual Studio 2019 v16.8.2, and when I try to compile a code written in VB.NET on which I declared a function whose parameter with name "ImageData" is a class from a 3rd party library written in C#, and that "ImageData" class expose a public property of type System.Span, I get the next compiler error:
Error BC30668 'ImageData' is obsolete:
'Types with embedded references are not supported in this version of your compiler.'.
After a little research it seems this is a non-sense decision by design:
They have confirmed that this behavior is by design. I don't understand
why they are not intend to let stack-only structures consumable in VB
when c# is able to define them. Maybe they thought ref structs are
similar to unsafe types. So, in most cases, VB developers may not
hurry to consume these types. But this assumption does not make sense,
because ref structs are not unsafe codes. They can be defined or be
used in C# 7.2 outside of the unsafe context, why can't we just
consume them in VB?
Both System.Span(Of T) and System.ReadOnlySpan(Of T) are important new
APIs for .NET developers who care about both performance and type
safety. We should feel natural when using them, rather than seeing the
annoying BC30668 compilation error.
Is there any workaround to ignore this compiler error so I can compile my code under VBNET?.
I am reading the book "CLR Via C#" and in the Generics chapter is said:
Source code protecton
The developer using a generic algorithm doesn't need to have access to the algorithm's source code. With C++ templates or Java's generics, however, the algorithm's source code must be available to the developer who is using the algorithm.
Can anyone explain what exactly is meant by this?
Well, Generic classes are distributed in compiled form, unlike C++, where templates need to be distributed in full source code. So you do not need to distribute the C# source code of a library that contains generic classes.
This does not prevent the Receiver of your class from disassembling it though (as it is compiled to IL which can be rather easily decompiled again). To really protect the code, additional methods, such as obfuscation are required.
Behind the scene: This distribution in compiled form is the reason why C# generics and C++ templates also differ in the way they need to be written. C# generic classes and their methods need to be fully defined at the time of compilation, and any error in the definition of the generic class or their methods or any operation on a template parameter which cannot be deduced at compile time will directly produce a compile error. In C++ the template is only compiled at the time of usage and only the methods actually used are compiled. If you have an undefined operation or even a syntactical error in a template definition, you will only see the error when that function is actually instantiated and used.
I want to declare a COM Interface in MIDL that allows for returning a pointer (like in the ID3D11Blob). I understand that pointers are a special thing in COM because of the stubs generated for RPC calls. I do not need RPC, but only want to access the COM server from C#. The question is: can I declare the interface in such a way that the C# stub returns an IntPtr? I have tried to add [local] to enable void pointers, but that does not suffice.
The interface should look in MIDL like
[local] void *PeekData(void)
and in C# like
IntPtr PeekData()
Is this possible? If so, how?
Thanks in advance,
Christoph
Edit: To rephrase the question: Why is
HRESULT GetData([in, out, size_is(*size)] BYTE data[], [in, out] ULONG *size);
becoming
void GetData(ref byte, ref uint)
and how can I avoid the first parameter becoming a single byte in C#?
This goes wrong because you imported the COM server declarations from a type library. Type libraries were originally designed to support a sub-set of COM originally called "OLE Automation". Which restricts the kind of types you can use for method arguments. In particular, raw pointers are not permitted. An array must be declared as a SAFEARRAY. Which ensures that the caller can always index an array safely, safe arrays have extra metadata that describes the rank and the lower/upper bounds of the array.
The [size_is] attribute is only understood by MIDL, it is used to create the proxy and the stub for the interface. Knowing how many elements the array contains is also important when it needs to be copied into an interop packet that's sent on the wire to the stub.
Since type libraries don't support a declaration like this, the [size_is] attribute is stripped and the type library importer only sees BYTE*. Which is ambiguous, that can be a byte passed by reference or it can be a pointer to an array of bytes. The importer chooses the former since it has no hope of making an array work, it doesn't know the size of the array. So you get ref byte.
To fix this issue, you have to alter the import library so you can provide the proper declaration of the method. Which requires the [MarshalAs] attribute to declare the byte[] argument an LPArray with the SizeParamIndex property set so you can tell the CLR that the array size is determined by the size argument. There are two basic ways to go about it:
Decompile the interop library with ildasm.exe, modify the .il file and put it back together with ilasm.exe. You'd use a sample C# declaration that you look at with ildasm.exe to know how to edit the IL. This is the approach that Microsoft recommends.
Use a good decompiler that can decompile IL back to C#. Reflector and ILSpy are popular. Copy/paste the generated code into a source file of your project and edit the method, applying the [MarshalAs] attribute. Advantage is that editing is easier and you no longer have a dependency on the interop library anymore.
In either case, you want to make sure that the COM server is stable so you don't have to do this very often. If it is not then modifying the server itself is highly recommended, use a safe array.
I think I found the solution on http://msdn.microsoft.com/en-gb/library/z6cfh6e6(v=vs.110).aspx#cpcondefaultmarshalingforarraysanchor2: This is the default behaviour for C-style arrays. One can avoid that by using SAFEARRAYs.
If you want to use a COM type in your C# code, the process is straight forward, right? You just need to use the type library importer and that's fine, but what if you don't have one and you can't take a look at the IDL file? You just have the COM DLL server.
As an example, try using the IActiveDesktop interface.
What's the approch used to solve this kind of problem?
There are two kinds of COM interfaces. The one you are familiar with are the ones that restrict themselves to a subset of the COM spec known as "OLE Automation". Also known as ActiveX before that term became associated with security disasters.
Automation compatible interfaces are easy to use from just about any language. They typically inherit from IDispatch, allowing them to be used from scripting languages. And limit themselves to using only automation compatible types for their method arguments. The simple stuff, comparable to the .NET value types, BSTR for strings, SAFEARRAY for arrays, VARIANT for untyped arguments, quite similar to .NET's System.Object.
Another feature they support well is type libraries, the equivalent of .NET metadata. Used by a compiler to know how to call the interface methods. The IDE uses a type library to automatically generate the interop library so you can directly create the wrapper class and call the methods from .NET code.
Well, that's the good news. The bad news is that there are lots of COM interfaces around that do not use the Automation restrictions. They typically inherit from IUnknown and use function arguments that don't marshal well. Like structures. One very large and visible component in Windows that is like this is the shell. Windows Explorer.
That's where IActiveDesktop fits in as well, it is a shell interface and inherits from IUnknown. It is declared in the ShlObj.h SDK header file, there is not even a IDL file for it. And consequently no way to get a type library with its definition. It uses incompatible argument types, like LPCWSTR (a raw pointer to a string) instead of BSTR. And structure pointers like LPCCOMPONENT and LPWALLPAPEROPT. The CLR interop support is powerless to marshal that properly.
Using the interface in C# is technically not impossible, but you have to redeclare the interface. Very carefully, getting it wrong is very easy to do. The fact that source code that already does this is very hard to find is a hint how difficult it is. This squarely falls in the 'not impossible, but what sane programmer wants to maintain code like this' category. The shell is the domain of unmanaged C++ code. And a crew of hardy programmers, because debugging shell extensions is quite painful.
This isssue may have several aspects so please read through first.
Suppose that you have a stuct with a few small ints that pack well into Int64 and while you want to use your struct as a type in C# you want it to be exposed as In64 via web methods - so that WSDL has it and you retain basic REST ability (simple types make GET invocation possible).
The closest to that I've found so far is SqlDateTime - it auto-morphs into dateTime in WSDL (there's an attrib that seems to govern XSD/WSDL type equivalence plus IXmlSerializable) but that's not enough. The web method still gets recognized as "having complex params" and therefore is rendered unavailable to GET requests.
Update: XSD/WSDL and SOAP invocation respected type equivalency perfectly fine - the problem is with GET invocation - the RESTful URL path doesn't get generated at all.
Looking for info on possible additional attribs, interfaces, hook-up points, of if someone stumbled upon a struct or internal class that managed to do full type equivalence with any "primitive", scalar type (DayTime is not exactly primitive but still gets such treatment). Also if soemone knows a way to establish stronger type equivalence or add/mark a struct to be treated as a simple (scalar) value type - even better.
Please don't post just to say something nasty or preach private ideology. This is serious, gray-zone question for people who know their way in Reflector and read the code. If you think you can ideologize this you don't even have the clue about the issue. If however you can point to actual code that causes/makes the decison about what will be servable via GET request please post even if by doing that you prove the impossibility of extending type equivalence to GET requests.
Oh and CLR is 2.x/3.x.
Thanks to those who help and to those who don't disrupt.
This is not doable.
Why would it be? You're talking about an egregious hack. Why on Earth would .NET ever support it, or allow it?
The only thing you'll be able to do is to implement the IXmlSerializable interface on your struct, so you can do the serialization and deserialization yourself.