|
Luc Pattyn wrote: choose a simpler interface, one that does not need any marshaling at all
Unfortunately, some of our suppliers provide unmanaged code with complex structures that's just easier to cope with in mixed languages. We use CLI to simplify the interfaces for our use.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
Yep, when the interface is fixed, there isn't much one can do.
My data typically is large and doesn't like to get copied just for marshalings' sake. In simulation, image processing, and such, the performance gained by doing things natively should not be thrown away by merely crossing the boundary.
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
eventSize is actually 12 * number of elements. The Marshal.SizeOf(ev) was there from previously attempted code and is now redundant - sorry about that.
Luc Pattyn wrote: [4] treats eventSize as if it were the size of a single element, which it isn't
Not sure what you mean here. I'm trying to Marshal element[i] into the next block of bytes reserved by [2], so if there were three elements, [2] would reserve 36 bytes. On the first iteration, element 1 will go to where eventPointer is pointing, on the second eventPointer + 12, on the third eventPointer + 24.
Oops - you're right. eventSize is the size of all events, not an individual. Changing that in [4] fixed it!
Thanks guys.
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
you're welcome.
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
In case you're interested - this is the working test code.
This is just for testing - the actual app will have lots of error checking/exception catching, the PInvoke stuff will be alot safer, stuff will be handled in threads and events used to unprepare buffers and close streams etc... but it shows how complicated something like this can be to get just right!
using System;
using System.Runtime.InteropServices;
namespace MIDITest
{
public delegate void MidiProc(IntPtr hMidiIn, int wMsg, int dwInstance, uint dwParam1, uint dwParam2);
class Program
{
static void Main(string[] args)
{
MIDI midi = new MIDI();
midi.BrokenCMajorTriad();
Console.ReadKey();
}
}
class MIDI
{
MidiProc midiProc;
public void BrokenCMajorTriad()
{
midiProc = MessageHandler;
int id = 0;
IntPtr handle = IntPtr.Zero;
int result = 0;
Console.WriteLine("Stream Out Message");
Console.WriteLine("------------------");
MIDIHDR header = new MIDIHDR();
MIDIEVENT ev0 = new MIDIEVENT();
ev0.dwEvent = 0x00403C90;
MIDIEVENT ev1 = new MIDIEVENT();
ev1.dwDeltaTime = 10;
ev1.dwEvent = 0x00404090;
MIDIEVENT ev2 = new MIDIEVENT();
ev2.dwDeltaTime = 10;
ev2.dwEvent = 0x00404390;
MIDIEVENT ev3 = new MIDIEVENT();
ev3.dwDeltaTime = 80;
ev3.dwEvent = 0x00403C80;
MIDIEVENT ev4 = new MIDIEVENT();
ev4.dwDeltaTime = 0;
ev4.dwEvent = 0x00404080;
MIDIEVENT ev5 = new MIDIEVENT();
ev5.dwDeltaTime = 0;
ev5.dwEvent = 0x00404380;
MIDIEVENT[] events = new MIDIEVENT[]
{
ev0, ev1, ev2, ev3, ev4, ev5
};
int eventSize = Marshal.SizeOf(typeof(MIDIEVENT));
int blockSize = eventSize * events.Length;
IntPtr eventPointer = Marshal.AllocHGlobal(blockSize);
for (int i = 0; i < events.Length; i++)
Marshal.StructureToPtr(events[i], (IntPtr)((int)eventPointer + (eventSize * i)), false);
result = midiStreamOpen(ref handle, ref id, 1, midiProc, 0, CALLBACK_FUNCTION);
header.lpData = eventPointer;
header.dwBufferLength = blockSize;
header.dwBytesRecorded = blockSize;
int headerSize = Marshal.SizeOf(header);
IntPtr headerPointer = Marshal.AllocHGlobal(headerSize);
Marshal.StructureToPtr(header, headerPointer, false);
result = midiOutPrepareHeader(handle, headerPointer, headerSize);
result = midiStreamOut(handle, headerPointer, headerSize);
result = midiStreamRestart(handle);
while (((BufferFlags)Marshal.ReadInt32(headerPointer, 16) & BufferFlags.Done) != BufferFlags.Done)
{ }
result = midiOutUnprepareHeader(handle, headerPointer, headerSize);
Marshal.FreeHGlobal(headerPointer);
Marshal.FreeHGlobal(eventPointer);
System.Threading.Thread.Sleep(2000);
result = midiStreamClose(handle);
handle = IntPtr.Zero;
}
void MessageHandler(IntPtr hMidiIn, int wMsg, int dwInstance, uint dwParam1, uint dwParam2)
{
switch (wMsg)
{
case MOM_OPEN:
Console.WriteLine("Opened");
break;
case MOM_CLOSE:
Console.WriteLine("Closed");
break;
case MOM_DONE:
Console.WriteLine("Done");
break;
}
}
[Flags]
public enum BufferFlags
{
None = 0,
Done = MHDR_DONE,
Prepared = MHDR_PREPARED,
Queued = MHDR_INQUEUE,
ISStream = MHDR_ISSTRM
}
public const int CALLBACK_FUNCTION = 0x00030000;
public const int MOM_OPEN = 0x3C7;
public const int MOM_CLOSE = 0x3C8;
public const int MOM_DONE = 0x3C9;
public const int MHDR_DONE = 0x00000001;
public const int MHDR_PREPARED = 0x00000002;
public const int MHDR_INQUEUE = 0x00000004;
public const int MHDR_ISSTRM = 0x00000008;
[DllImport("winmm.dll")]
public static extern int midiOutPrepareHeader(
IntPtr hmo,
IntPtr lpMidiOutHdr,
int cbMidiOutHdr);
[DllImport("winmm.dll")]
public static extern int midiOutUnprepareHeader(
IntPtr hmo,
IntPtr lpMidiOutHdr,
int cbMidiOutHdr);
[DllImport("winmm.dll")]
public static extern int midiStreamClose(
IntPtr hStream);
[DllImport("winmm.dll")]
public static extern int midiStreamOpen(
ref IntPtr lphStream,
ref int puDeviceID,
int cMidi,
MidiProc dwCallback,
int dwInstance,
int fdwOpen);
[DllImport("winmm.dll")]
public static extern int midiStreamOut(
IntPtr hMidiStream,
IntPtr lpMidiHdr,
int cbMidiHdr);
[DllImport("winmm.dll")]
public static extern int midiStreamRestart(
IntPtr hms);
}
[StructLayout(LayoutKind.Sequential)]
public struct MIDIHDR
{
public IntPtr lpData;
public int dwBufferLength;
public int dwBytesRecorded;
public IntPtr dwUser;
public int dwFlags;
public IntPtr lpNext;
public IntPtr reserved;
public int dwOffset;
public IntPtr dwReserved;
}
[StructLayout(LayoutKind.Sequential)]
public struct MIDIEVENT
{
public uint dwDeltaTime;
public uint dwStreamID;
public uint dwEvent;
}
}
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
Waw. I'll take a day off to read the upcoming article then.
And all this to get a broken triad?
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
Luc Pattyn wrote: I'll take a day off to read the upcoming article then.
Luc Pattyn wrote: And all this to get a broken triad?
Yeah, but now I can put anything in there (up to 64K/buffer) and use multiple MIDIHDR buffers if needed to create full sequences!
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
Hi Luc,
Sorry to reply to an old message - I didn't want to email you directly and your email link is missing in CP pages.
If you have a moment would you take a look at a question I posted yesterday here[^]? I know you're far more competent with this P/Invoke stuff than me and I'd value your opinion!
Cheers,
DaveIf this helped, please vote & accept answer!
Binging is like googling, it just feels dirtier. (Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
|
|
|
|
|
Hi Davey69!According to MSDN documetation lpData type is LPSTR which specifies a pointer to an array of 8-bit characters maybe terminated by null character.According to me it's equal to System.Byte type-it's a pointer to byte array.But you said it's array of MIDIEVENT structs.It's strange.When you need to marshal constant size array within a struct just marchal it as an managed array,but when it's size is variable use IntPtr as you have done.
Life is a stage and we are all actors!
|
|
|
|
|
Yeah, you're right. A char is a byte so a char[] is a byte[] - in the c++ world anyway (unfortunately not in C#)!
The MIDIEVENT structures are word aligned, so it's treated as a byte array internally by Windows. Passing a pointer to a byte array works fine, but using the defined MIDIEVENT structures makes assigning the various elements of that structure much easier.
Got the problem fixed now anyway, but thanks for your input.
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
DaveyM69 wrote: Passing a pointer to a byte array works fine, but using the defined MIDIEVENT structures makes assigning the various elements of that structure much easier.
DaveyM69 wrote: A char is a byte so a char[] is a byte[] - in the c++ world anyway
In fact ANSI C char range is from -127 to 127 and BYTE is equal to unsigned char ,so that they aren't equal.
That's why BYTE is equal to System.Byte always.
But I like your approach -just give the API to do annoying initialization work.It's more efficient rather than doing using custom logic in .NET.
Life is a stage and we are all actors!
modified on Friday, August 14, 2009 7:01 PM
|
|
|
|
|
Hi,
Am reading an excel file containing columns and storing it into the database. The excel sheet contains a column called STATUS which includes (NOT STARTED , IN-PROGRESS , COMPLETE) several rows have different statuses. Everytime the excel sheet is read the values are stored into the table in the db.
Now in the latest excel sheet some of the rows have a changed status i.e a row which had STATUS as "NOT-STARTED" in the previous excel sheet, will now have status as "IN-PROGRESS". How do I compare this with the actual data in the database table and update that particular row with the new STATUS using LINQ.
Help appreciated,,,
|
|
|
|
|
Please don't cross post. It's against the role.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
got u ..... i dint know which forum to post it in...so posted in both........
|
|
|
|
|
Well, you kind of gave it away in your post title - it's a LINQ issue.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
I’m still fairly new with this stuff and was writing an application that will get some computer and bios info from computers on our network using WMI. I’ve got things working so that I’m getting the information that I want, however, I would like to add some error handling in case the property I’m searching for doesn’t exist. Currently the program just stops if it can’t find the property/value.
Would it be best to use a try catch? If so would I need to write it in for every property value?
Thanks
-Rob
ManagementScope scope = new ManagementScope("\\\\" + target + "\\root\\cimv2");
ManagementPath pathBios = new ManagementPath("Win32_Bios");
ManagementPath pathSystem = new ManagementPath("Win32_ComputerSystem");
ObjectGetOptions obj = new ObjectGetOptions(null);
ManagementClass wmiBios = new ManagementClass(scope, pathBios, obj);
ManagementClass wmiSystem = new ManagementClass(scope, pathSystem, obj);
foreach (ManagementObject bios in wmiBios.GetInstances())
{
queueStack.Enqueue("Manufacturer: " + bios.Properties["Manufacturer"].Value.ToString().Trim());
queueStack.Enqueue("rev: " + bios.Properties["smbiosbiosversion"].Value.ToString().Trim());
queueStack.Enqueue("SN: " + bios.Properties["Serialnumber"].Value.ToString().Trim());
queueStack.Enqueue("Status: " + bios.Properties["Status"].Value.ToString().Trim());
}
I've added a try/catch for each wmi value being returned
modified on Monday, August 17, 2009 3:11 PM
|
|
|
|
|
eeffoc42 wrote: Would it be best to use a try catch?
That is one way and the best way. There coud be error hundling as returning result, but throwing expection has its own uses. If You don't have unhandled expection the program will have a poped up a form or send it to debbuger if attached.
eeffoc42 wrote: If so would I need to write it in for every property value?
That is up to you and based on a case. If property has some limits like value is too low then yes.
I do not know what Expection is thrown, here is some examples:
<br />
try<br />
{<br />
XmlReaderSettings xrs = new XmlReaderSettings();<br />
xrs.IgnoreWhitespace = true;<br />
xrs.IgnoreComments = true;<br />
String nonExsistingFile = "C:\Haha.txt";<br />
<br />
XmlReader reader = XmlReader.Create(nonExsistingFile , xrs);<br />
<br />
}<br />
catch (FileNotFoundException ex)<br />
{<br />
}<br />
If you have your own class, and if it doesn't throw exception, those try catch woudn't have any effect.
If you are looking custom Exception look here:
http://blog.gurock.com/articles/creating-custom-exceptions-in-dotnet/[^]
|
|
|
|
|
Hi,
it is often wise to add a try-catch construct, provided you do something with what you catch; an empty catch block is mostly unacceptable, since that just would ignore and swallow the problem.
Suggestion: when showing an exception, always use Exception.ToString() to get all of it.
You would need as many try-catch constructs as you want your error handling to be granular; if your code normally runs fine, put it all in one try-catch; if you want your foreach loop to continue with the next object, then you need to put the try-catch inside the foreach.
Often it is better to avoid an exception all together; example:
PropertyData pd=bios.Properties["Manufacturer"];
if (pd!=null) queueStack.Enqueue("Manufacturer: "+pd.Value.ToString().Trim());
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
eeffoc42 wrote: ManagementScope scope = new ManagementScope("\\\\" + target + "\\root\\cimv2")
ManagementScope class usually is combined with ConnectionOptions class in order to allow you to prompt account security credentials for the remote computer connect or/and to configurate COM impersonation level used for remote connection operations. For error handling you could just use singe try/catch block.
Life is a stage and we are all actors!
modified on Friday, August 14, 2009 4:27 PM
|
|
|
|
|
My current block in the road is figuring out how to compare files through sockets. I know its possible just not sure how. Would I use TCP/IP? I'm lost
|
|
|
|
|
|
well both methods would work I guess, but which would be more effiecnt?
|
|
|
|
|
If you chose to send entire file, you coud also compare what was changed. But if you wan't to know only if it is changed, sending hash woud be enough
|
|
|
|
|
Is it possible to specify a web service entirely via the app.config file? What I'm trying to avoid is statically adding a web service reference to a desktop app.
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001
|
|
|
|
|
You can change the URL of the web service via configuration files. The only way I can think of to use a web service with out the autogenerated code is to just call it yourself and parse the XML into your own objects but really overkill.
|
|
|
|
|