|
Thanks Richard and Luc for your replies, really appreciated!
Richard, for the string type I agree with you, that's why I tried a Stringbuilder type instead, but no more result.
About the documentation, I though that the header file of the API was enough (.h file). I also have a .lib file but I think that is for C++ so not useful for me with Dot Net. What else could have been useful?
|
|
|
|
|
Your original post shows the following extract from the header file:
#define API_SPEC __declspec(dllexport)
void API_SPEC API_getApiVersion (std::wstring *version)
Since you cannot directly convert a VB.NET String to a C++ std::wstring* I think the only solution is to write a C++ interface that can take a pointer to a StringBuilder object. This code could then call the API passing a pointer to a std::wstring which it will copy to the StringBuilder before returning to the VB.NET code.
Comments, Luc?
MVP 2010 - are they mad?
|
|
|
|
|
Hello all,
I think the solution here is to use the COM interoperability provided by dotNET. Note that I have not yet tried this myself, but I believe you have to use MarshallAs to ensure that VB.NET, in this case, converts the string before the call to a LPWSTR and after the call converts it back to a VB string.
Whether you have to use a stringbuilder or a string here I'm not sure, but my best guess is that you can use a normal string.
Here's a msdn link that might help, though it's not entirely clear to me:
http://msdn.microsoft.com/en-us/library/s9ts558h(VS.71).aspx
I'm not currently in a position to access VB.NET (or any other .NET language for that matter), so I'm sorry I can't give you the complete code.
Maybe one of the other repliers can help you out more.
Good Luck,
MicroVirus
|
|
|
|
|
The link provide good information and I tried but what I got is a Debug Assertion Failed box on the expression: _CrtIsValidHeapPointer(pUserData)
|
|
|
|
|
MicroVirus wrote: I think the solution here is to use the COM interoperability provided by dotNET.
He is already using that. The problem is that the C++ library function expects as input parameter a std::wstring* and I don't think there is any marshalling for such a class, so there has to be a user written intermediate function that accepts a char/byte[] and converts to and from the string class.MVP 2010 - are they mad?
|
|
|
|
|
Ouch right... I obviously overlooked that :S
In that case you're absolutely right and a wrapper needs to be written. Easiest way is to do that in (unmanaged) C++. I'd suggest taking the Windows API path on this one and write a function that takes a LPWSTR and size of the buffer, and returns the result of the function you are trying to access in this buffer.
|
|
|
|
|
As I recommended a few days ago!
<i>MVP 2010 - are they mad?</i>
|
|
|
|
|
AFAIK all extern 'C' does is tell the C++ compiler not to mangle the method names, which makes it easier to get the P/Invoke entrypoint right. Real C++ code can be P/Invoked without problems.
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read code that is properly formatted, adding PRE tags is the easiest way to obtain that. [The QA section does it automatically now, I hope we soon get it on regular forums as well]
|
|
|
|
|
Any comments on my latest, above?
MVP 2010 - are they mad?
|
|
|
|
|
Hi Richard,
AFAIK and assuming std::wstring is just Unicode, the DllImport attribute needs a Charset.Unicode (or the Declare statement needs a Unicode keyword), as ANSI is the default marshaling for strings.
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read code that is properly formatted, adding PRE tags is the easiest way to obtain that. [The QA section does it automatically now, I hope we soon get it on regular forums as well]
|
|
|
|
|
Hi Luc,
I haven't done a lot of work in this area but std::wstring is a C++ class that holds a Unicode string. I'm not sure whether the marshalling can handle it directly, so I may try some experiments to see what I can discover.
MVP 2010 - are they mad?
|
|
|
|
|
Hi guys,
After reading Luc's article (by the way, very interesting) and reading your posts, I tried to change the string type to Stringbuilder type. Because the C++ DLL sub has an OUT parameter, I modified the declaration to pass my variable byRef instead of ByVal:
<DllImport("C:\Api.dll", EntryPoint:="?API_getApiVersion@@YAXPAV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@@Z", CallingConvention:=CallingConvention.ThisCall, CharSet:=CharSet.Unicode)> _
Public Shared Sub test(ByRef version As StringBuilder)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim theVersion As StringBuilder = New Stringbuilder(20)
Call test(theVersion )
MessageBox.Show(theVersion.tostring)
End Sub
End Class
What is happening now is that when the line 'Call test(theVersion)' is executed, the application quit without any warning or error, even if I put a breakpoint at the 'Messagebox.show' line. Am I right to pass my variable byRef instead of byVal. Of course, I tried to change it to use byVal and what i get is an empty string in return.
When you look at the declaration line in the C++ code there is that #DECLARE API_SPEC line and that API_SPEC is also at the beginning of the method API_getApiVersion. Most of the time the DECLARE statement for __declspec(dllexport) use the C or C++ keyword to specify the language type. Here I have a keyword that is use at the beginning of the method definition. What is the purpose of that declare then?
Thanks again.
|
|
|
|
|
Hi,
yes ByRef seems right.
I'm still not happy with your entrypoint, "char_traits" and "allocator" don't belong there AFAIK.
I just now noticed ThisCall, which probably is wrong.
suggestion: if you have the source to the DLL, and can build it again, you could add a method that does what you need, with whatever API you choose. That one could have extern 'C' (hence no mangling), an explicit calling convention, and fill or return a regular string.
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read code that is properly formatted, adding PRE tags is the easiest way to obtain that. [The QA section does it automatically now, I hope we soon get it on regular forums as well]
modified on Friday, February 5, 2010 9:08 AM
|
|
|
|
|
Following on from Luc's comments, this cannot work as it stands. The C++ method is expecting a reference to a C++ std::wstring class, and you cannot create one in VB. The only answer is to write a C++ wrapper to the DLL which will accept a reference to a character array and then use that intermediate code to convert between that and the wstring type.
MVP 2010 - are they mad?
|
|
|
|
|
Thanks gentlemen for your inputs. I will remove the dust on my old C++ book and go with the wrapper.
|
|
|
|
|
We have a legacy system (in C++/MFC/C# .NET), that talks to SQL server database.
At that time, the Db was not designed for internationalization. Hence the string fields in Db are of type varchar.
One option is to change the varchars to nvarchars. This increases the Db size by 50%.
The existing users of the app would not want to have this, with no tangible benefit.
But it is essential for us to support internationalization.
Is it possible to have 2 sets of Db, one for existing customers and another for new customers (with nvarchar)
with the same code base, or some minor modifications to the code?
Open to ideas/suggestions/comments or questions.
Thanks,
Saleem
|
|
|
|
|
Md Saleem Navalur wrote: One option is to change the varchars to nvarchars. This increases the Db size by 50%.
The existing users of the app would not want to have this, with no tangible benefit.
What difference would it make to the users? Do they specify a limit to the size of the database or are there other limiting factors?
In any case the tangible benefit is that it can now support internationalisation.
Md Saleem Navalur wrote: Is it possible to have 2 sets of Db, one for existing customers and another for new customers (with nvarchar)
with the same code base, or some minor modifications to the code?
At the very least it would be pretty difficult to maintain with 2 'almost' identical databases.
|
|
|
|
|
Yes the size of the Db matters, its already close to 1 TB. Making nvarchars would increase this substantially. Existing users dont really care about localization as they are always in en-US culture.
It is for the new users, we have an issue.
Saleem
|
|
|
|
|
Md Saleem Navalur wrote: s it possible to have 2 sets of Db, one for existing customers and another for new customers (with nvarchar)
with the same code base, or some minor modifications to the code?
Your data access layer should be flexible enough to support this. If it's V1.0, use database A, if V2.0, use database B.
I know the language. I've read a book. - _Madmatt
|
|
|
|
|
Hi all ,
As part of my presentation @ Community Tech Days which was held at Kochi (INDIA ) , I had written a Compiler to demonstrate run time code generation using Reflection.Emit.
The Source Language is called SLANG4.net. The Project is hosted @ http://slangfordotnet.codeplex.com.
The compiler is devoleped in stages to aid comprehension. Detailed documentation is available in the Zip bundle.
regards
Praseed Pai
http://praseedp.blogspot.com
|
|
|
|
|
Hi all,
Is it possible to read / write data to / from the clipboard using a COM interface? I'm writing a Silverlight app and the SIlverlight framework only allows for reading & writing text, I however need to write a JPEG byte array, and I'm running as a trusted application so I have extensive COM available.
My second question is around how to write binary data to the clipboard so that Excel sees it as an Image (SL does not have an Image object type), anyone ever done that before?
____________________________________________________________
Be brave little warrior, be VERY brave
|
|
|
|
|
Your question will probably get better visibility in the correct forum.
MVP 2010 - are they mad?
|
|
|
|
|
I am designing a distributed application hosted in NET 3.0. This is intended to have a common user interaction point - Control GUI.
Any number of components providing different functionality may be running at one time but the Control GUI should reflect only those components which are running.
The idea is something like this - as different components activate themselves the Control GUI should expand to accomodate any new fuctionality the new component provides.
This would seem to require serialising a new GUI component to the Control GUI and inserting it into the Control GUI process (app domain) as a plug-in.
There is lots of info around about plug-in managers but not too much about how to serialise the GUI.
I am not looking for a complete solution but ideas or pointers as to where to look would be appreciated.
Thanks in advance
Peter Wasser
modified on Thursday, February 4, 2010 3:10 AM
|
|
|
|
|
Hi,
I am using the following MSDN Asynchronous Server Socket example:
http://msdn.microsoft.com/en-us/library/fx6588te(VS.80).aspx[^]
Problem is that when I embed this code in a Windows service, it gives me a error "Error 1053: The service did not respond to the start or control request in a timely fashion" & the service remains in "Starting" state.
Need help, I'm kinda stuck here.
Thanks.
Additional Info:
This windows service is to act as server listening to 'n' number of socket clients connecting & sending data.
modified on Thursday, February 4, 2010 5:08 AM
|
|
|
|
|
Hi,
I guess you put the code into the starting method of the service. This will create a timeout since the service is waiting for a connection (cause by the WaitOne-call). So you should not wait for a connection within the starting method of the service. If I'm wrong please provide the code within the start method of the service so the error is easier to found.
Regards
Sebastian
|
|
|
|