C Style char array returned by an event from a DLL COM<p>I am using a DLL (COM interop) in Visual Basic 2005 and can not get the correct values returned from an event. The last argument is a variable length array of char that is returned as a pointer to the first element in the array. The only thing I get is the first byte no matter how many characters are to be returned. For exampe, if the returned value is 257 in two bytes, my value I get is 1. This is the event handler:</p> <p><font color="#0000ff" size=2>Private</font><font size=2> </font><font color="#0000ff" size=2>Sub</font><font size=2> ads_devicenotification(</font><font color="#0000ff" size=2>ByRef</font><font size=2> pTime </font><font color="#0000ff" size=2>As</font><font size=2> TcAdsDll.TimeStamp, </font><font color="#0000ff" size=2>ByVal</font><font size=2> hNotification </font><font color="#0000ff" size=2>As</font><font size=2> </font><font color="#0000ff" size=2>Integer</font><font size=2>, </font><font color="#0000ff" size=2>ByVal</font><font size=2> cbLen </font><font color="#0000ff" size=2>As</font><font size=2> </font><font color="#0000ff" size=2>Integer</font><font size=2>, &lt;MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=128&gt; </font><font color="#0000ff" size=2>ByRef</font><font size=2> pData </font><font color="#0000ff" size=2>As</font><font size=2> </font><font color="#0000ff" size=2>Byte</font><font size=2>) </font><font color="#0000ff" size=2>Handles</font><font size=2> TcComm1.DeviceNotification</p> <p></font><font color="#0000ff" size=2>Dim</font><font size=2> Data(cbLen - 1) </font><font color="#0000ff" size=2>As</font><font size=2> </font><font color="#0000ff" size=2>Byte</p></font><font size=2> <p></font><font color="#0000ff" size=2>Try</p></font><font size=2> <p></font><font color="#0000ff" size=2>For</font><font size=2> i </font><font color="#0000ff" size=2>As</font><font size=2> </font><font color="#0000ff" size=2>Integer</font><font size=2> = 0 </font><font color="#0000ff" size=2>To</font><font size=2> cbLen - 1</p> <p>Data(i) = Marshal.ReadByte(pData, i)</p> <p></font><font color="#0000ff" size=2>Next</p></font><font size=2> <p></font><font color="#0000ff" size=2>Catch</font><font size=2> ex </font><font color="#0000ff" size=2>As</font><font size=2> Exception</p> <p></font><font color="#0000ff" size=2>End</font><font size=2> </font><font color="#0000ff" size=2>Try</p></font><font size=2> <p></font><font color="#008000" size=2>'* This value is equal to &quot;ActualValue AND 255&quot;</p></font><font size=2> <p></font><font color="#0000ff" size=2>Dim</font><font size=2> x </font><font color="#0000ff" size=2>As</font><font size=2> </font><font color="#0000ff" size=2>Integer</font><font size=2> = BitConverter.ToInt16(Data, 0)</p> <p></font><font color="#0000ff" size=2>End</font><font size=2> </font><font color="#0000ff" size=2>Sub</p></font>© 2009 Microsoft Corporation. All rights reserved.Thu, 19 Jun 2008 00:15:52 Z3cf9da4d-0d9a-411e-884c-f34e88e8d5achttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#3cf9da4d-0d9a-411e-884c-f34e88e8d5achttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#3cf9da4d-0d9a-411e-884c-f34e88e8d5acArchiehttp://social.msdn.microsoft.com/Profile/en-US/?user=ArchieC Style char array returned by an event from a DLL COM<p>I am using a DLL (COM interop) in Visual Basic 2005 and can not get the correct values returned from an event. The last argument is a variable length array of char that is returned as a pointer to the first element in the array. The only thing I get is the first byte no matter how many characters are to be returned. For exampe, if the returned value is 257 in two bytes, my value I get is 1. This is the event handler:</p> <p><font color="#0000ff" size=2>Private</font><font size=2> </font><font color="#0000ff" size=2>Sub</font><font size=2> ads_devicenotification(</font><font color="#0000ff" size=2>ByRef</font><font size=2> pTime </font><font color="#0000ff" size=2>As</font><font size=2> TcAdsDll.TimeStamp, </font><font color="#0000ff" size=2>ByVal</font><font size=2> hNotification </font><font color="#0000ff" size=2>As</font><font size=2> </font><font color="#0000ff" size=2>Integer</font><font size=2>, </font><font color="#0000ff" size=2>ByVal</font><font size=2> cbLen </font><font color="#0000ff" size=2>As</font><font size=2> </font><font color="#0000ff" size=2>Integer</font><font size=2>, &lt;MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=128&gt; </font><font color="#0000ff" size=2>ByRef</font><font size=2> pData </font><font color="#0000ff" size=2>As</font><font size=2> </font><font color="#0000ff" size=2>Byte</font><font size=2>) </font><font color="#0000ff" size=2>Handles</font><font size=2> TcComm1.DeviceNotification</p> <p></font><font color="#0000ff" size=2>Dim</font><font size=2> Data(cbLen - 1) </font><font color="#0000ff" size=2>As</font><font size=2> </font><font color="#0000ff" size=2>Byte</p></font><font size=2> <p></font><font color="#0000ff" size=2>Try</p></font><font size=2> <p></font><font color="#0000ff" size=2>For</font><font size=2> i </font><font color="#0000ff" size=2>As</font><font size=2> </font><font color="#0000ff" size=2>Integer</font><font size=2> = 0 </font><font color="#0000ff" size=2>To</font><font size=2> cbLen - 1</p> <p>Data(i) = Marshal.ReadByte(pData, i)</p> <p></font><font color="#0000ff" size=2>Next</p></font><font size=2> <p></font><font color="#0000ff" size=2>Catch</font><font size=2> ex </font><font color="#0000ff" size=2>As</font><font size=2> Exception</p> <p></font><font color="#0000ff" size=2>End</font><font size=2> </font><font color="#0000ff" size=2>Try</p></font><font size=2> <p></font><font color="#008000" size=2>'* This value is equal to &quot;ActualValue AND 255&quot;</p></font><font size=2> <p></font><font color="#0000ff" size=2>Dim</font><font size=2> x </font><font color="#0000ff" size=2>As</font><font size=2> </font><font color="#0000ff" size=2>Integer</font><font size=2> = BitConverter.ToInt16(Data, 0)</p> <p></font><font color="#0000ff" size=2>End</font><font size=2> </font><font color="#0000ff" size=2>Sub</p></font>Thu, 20 Apr 2006 12:41:14 Z2006-06-16T18:45:23Zhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#83058c1b-fdcd-4ee2-b248-f754f4c53120http://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#83058c1b-fdcd-4ee2-b248-f754f4c53120TaylorMichaelLhttp://social.msdn.microsoft.com/Profile/en-US/?user=TaylorMichaelLC Style char array returned by an event from a DLL COM<p>Without actually trying it I'm not 100% sure but I think your marshalling flags are wrong.  By using SizeParamIndex you are telling it that the 128th parameter contains the size of the array which is not what you wanted.  I believe you should instead say SizeParamIndex=2 such that the size is contained in cbLen.  I also believe that you should change the pData syntax to be an array instead of a single value.  It should be an array of bytes.</p> <p>Hope this helps,</p> <p>Michael Taylor - 4/20/06</p>Thu, 20 Apr 2006 13:59:01 Z2006-06-16T18:45:23Zhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#3c70ae88-efad-4e2d-ad3a-c7cee2965238http://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#3c70ae88-efad-4e2d-ad3a-c7cee2965238Archiehttp://social.msdn.microsoft.com/Profile/en-US/?user=ArchieC Style char array returned by an event from a DLL COM<p>If I change the pData to an array by adding parentheses after it, this is the error I get:</p> <p>Error 1 Method 'Private Sub ads_devicenotification(ByRef pTime As TcAdsDll.TimeStamp, hNotification As Integer, cbLen As Integer, ByRef pData() As Byte)' cannot handle Event 'Public Event DeviceNotification(ByRef pTime As TcAdsDll.TimeStamp, hNotification As Integer, cbLen As Integer, ByRef pData As Byte)' because they do not have the same signature.</p> <p> </p> <p>I tried SizeParamIndex=2 with no difference in results. I made it 128 because the array length can vary depending on the type of data being retreived. I used the bitconverter.int16 just for a test of retreiving data that is two bytes in length. If it returns data that is only a single byte, I get the correct value.</p> <p>It almost seems that the marshalling sees it only defined as a single byte therefore only copies a single byte of the result to managed memory.</p>Thu, 20 Apr 2006 14:24:49 Z2006-04-20T14:24:49Zhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#e3e0dd9e-9f7d-4779-859b-184dd2a74773http://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#e3e0dd9e-9f7d-4779-859b-184dd2a74773TaylorMichaelLhttp://social.msdn.microsoft.com/Profile/en-US/?user=TaylorMichaelLC Style char array returned by an event from a DLL COM<p>It does see it as only a single byte because that is how you declared it.  Try specifying the array as an <strong>IntPtr</strong> instead of a byte (and remove the attributes) and then unmarshal the data using the Marshal class.  I believe this is used in some of the more bizarre interop situations where you don't know the length ahead of time.  Also if it is a character array then you can also just marshal it as a string.  Refer to MSDN for the sample on that.</p> <p>Michael Taylor - 4/20/06</p>Thu, 20 Apr 2006 14:54:27 Z2006-04-20T14:54:27Zhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#32b780ec-46d6-4042-a1f0-b310ad7f586fhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#32b780ec-46d6-4042-a1f0-b310ad7f586fArchiehttp://social.msdn.microsoft.com/Profile/en-US/?user=ArchieC Style char array returned by an event from a DLL COM<p>I seem to be stuck with the declaration of a single byte. If I change it to anything else, I get the same error mentioned previously. That decalaration was generated automatically when I added a reference to the dll in Visual Studio and it generated the file interop.TcAdsDll.dll</p> <p>I attempted to ildasm the file, edit the decalartion, and then ilasm the edited file. That only seemed to currupt the file and not allow anything to work.</p> <p>Is there any other way to force a different declaration other than a byte?</p>Thu, 20 Apr 2006 15:13:41 Z2006-04-20T15:13:41Zhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#e38b00cb-d56d-4cf9-86a9-ad30fb38689fhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#e38b00cb-d56d-4cf9-86a9-ad30fb38689fTaylorMichaelLhttp://social.msdn.microsoft.com/Profile/en-US/?user=TaylorMichaelLC Style char array returned by an event from a DLL COM<p>What does the unmanaged API look like?</p> <p> </p>Thu, 20 Apr 2006 16:19:30 Z2006-04-20T16:19:30Zhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#cecbb2f5-b3fb-4288-932e-83b619a15637http://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#cecbb2f5-b3fb-4288-932e-83b619a15637Archiehttp://social.msdn.microsoft.com/Profile/en-US/?user=ArchieC Style char array returned by an event from a DLL COM<p>Not sure. I only have the dll, tlb, and header files. No source code. I searched the header file, but it does not define a prototype for the devicenotification event.</p> <p>If I disassemble the dll, this is how the prototype is defined:</p> <p>{<br>  .custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 30 37 33 45 35 45 46 45 2D 31 36 38 34   // ..$073E5EFE-1684<br>                                                                                                  2D 34 36 38 37 2D 42 44 31 43 2D 36 42 30 43 34   // -4687-BD1C-6B0C4<br>                                                                                                  35 43 37 42 37 44 43 00 00 )                      // 5C7B7DC..<br>  .custom instance void [mscorlib]System.Runtime.InteropServices.InterfaceTypeAttribute::.ctor(int16) = ( 01 00 01 00 00 00 ) <br>  .method public hidebysig newslot abstract virtual <br>          instance void  DeviceNotification([in] valuetype TcAdsDll.TimeStamp&amp; pTime,<br>                                            [in] int32 hNotification,<br>                                            [in] int32 cbLen,<br>                                            [in] uint8&amp; pData) runtime managed internalcall<br>  {<br>  } // end of method _ITcAdsSyncEvents::DeviceNotification</p>Thu, 20 Apr 2006 17:09:18 Z2006-04-20T17:09:18Zhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#9c957ae4-8076-4c5e-95a1-aca12ec16aabhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#9c957ae4-8076-4c5e-95a1-aca12ec16aabTaylorMichaelLhttp://social.msdn.microsoft.com/Profile/en-US/?user=TaylorMichaelLC Style char array returned by an event from a DLL COM<p>What I meant was what was the original signature of DeviceNotification in unmanaged code.  If this is a COM interface then the method signature can be found in the IDL file or the H file if it has been generated from the IDL.  Otherwise you can use OleView to load the DLL or TLB and get the interface information manually.</p> <p><font face=Verdana>Is the DLL you are calling through COM an unmanaged dll?</font></p> <p><font face=Verdana>Michael Taylor - 4/20/06</font></p>Thu, 20 Apr 2006 17:21:15 Z2006-04-20T17:21:15Zhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#c2a9764b-0d9f-464c-aabd-7253669b71a4http://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#c2a9764b-0d9f-464c-aabd-7253669b71a4Archiehttp://social.msdn.microsoft.com/Profile/en-US/?user=ArchieC Style char array returned by an event from a DLL COM<p>I used OleView and found the interface information:</p><font size=1> <p>HRESULT _stdcall DeviceNotification(</p> <p>[in] TimeStamp* pTime, </p> <p>[in] long hNotification, </p> <p>[in] long cbLen, </p> <p>[in] unsigned char* pData);</p> <p> </p> <p>The Dll is a COM object.</p></font>Thu, 20 Apr 2006 17:54:03 Z2006-04-20T17:54:03Zhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#df4096f4-1c08-461b-988e-0380b2158a1bhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#df4096f4-1c08-461b-988e-0380b2158a1bTaylorMichaelLhttp://social.msdn.microsoft.com/Profile/en-US/?user=TaylorMichaelLC Style char array returned by an event from a DLL COM<p>It looks to me like the COM wrapper that is generated is incorrect.  I think the fact that it is trying to pass an unsigned char pointer is causing the marshaler to think it is a string or something.  You might have to modify the generated wrapper using ILDASM and ILASM to get it to work properly.  Alternatively it might just be easier to create a managed C++ class that works with the COM object through normal C++ and then use the managed C++ class in your VB code directly.  This would resolve all the issues I believe.</p> <p>Michael Taylor - 4/20/06</p>Thu, 20 Apr 2006 19:38:28 Z2006-04-20T19:38:28Zhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#3d8740a5-46de-4241-9023-eb3a8e6f6cc4http://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#3d8740a5-46de-4241-9023-eb3a8e6f6cc4Archiehttp://social.msdn.microsoft.com/Profile/en-US/?user=ArchieC Style char array returned by an event from a DLL COM<p>I'm running into a dead end. I was finally able to disassemble, edit and reassemble interop.TcAdsDll.dll. This is the two places I found to edit:</p> <p>  .method public virtual instance void  Invoke([in] valuetype TcAdsDll.TimeStamp&amp; pTime,<br>                                               [in] int32 hNotification,<br>                                               [in] int32 cbLen,<br>                                               [in] uint8&amp; pData) runtime managed<br> </p> <p>  .method public hidebysig newslot abstract virtual <br>          instance void  DeviceNotification([in] valuetype TcAdsDll.TimeStamp&amp; pTime,<br>                                            [in] int32 hNotification,<br>                                            [in] int32 cbLen,<br>                                            [in] uint8&amp; pData) runtime managed internalcall<br></p> <p>I've tried uiint[]&amp;,    uint[] marshal([]), and anything else I could get to work.</p> <p>If I didn't do the same thing to both places, most of the time I would the event would not even fire. Other times it gave me an error about not being able to call the dll.</p> <p>Any clues as to how I should edit the above code?</p>Thu, 20 Apr 2006 21:13:18 Z2006-04-20T21:13:18Zhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#db155878-615a-4659-8113-75a1d0497241http://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#db155878-615a-4659-8113-75a1d0497241TaylorMichaelLhttp://social.msdn.microsoft.com/Profile/en-US/?user=TaylorMichaelLC Style char array returned by an event from a DLL COM<p>Unfortunately it's not just a matter of changing a type name and rebuilding.  Forcing it from a scalar to an array will impact how the value is loaded onto the stack.  I don't believe you can use the ldarg routine anymore.  However as soon as you start mucky around with the IL then all the address labels change which could impact looping code.  Even worse is that if the COM object ever changes you'll have to repeat the adjustments.</p> <p>Like I said earlier it appears that the marshaller isn't generating the correct code for your signature.  Your best bet is probably to create a thunk object that sits between the COM object and your .NET code.  C++ is the way to go here.  C++ can talk with your COM object using native COM calls.  At the same time it can be a managed class that you can then directly instantiate in your .NET code without having to worry about COM interop at all.  I would recommend this approach as you don't have to muck around with the IL and it is easier to make changes.</p> <p>Perhaps someone else on the forums can provide you a better answer.  Good luck.</p> <p>Michael Taylor - 4/21/06</p>Fri, 21 Apr 2006 12:15:19 Z2006-04-21T12:15:19Zhttp://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#4551c11e-edab-4006-b144-9e046ba09831http://social.msdn.microsoft.com/Forums/en-US/clr/thread/3cf9da4d-0d9a-411e-884c-f34e88e8d5ac#4551c11e-edab-4006-b144-9e046ba09831Archiehttp://social.msdn.microsoft.com/Profile/en-US/?user=ArchieC Style char array returned by an event from a DLL COM<p>Unfotunately I haven't program in c++ for almost 10 years, so it would involve a learning curve for me.</p> <p>Thanks for all the help and suggestions! Much appreciated.</p>Fri, 21 Apr 2006 12:32:40 Z2006-04-21T12:32:40Z