[C#] Pointer uit windows message vergelijken met object

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Ik maak gebruik van de Windows Multimedia API om geluid te samplen. Ik voer meerdere buffers aan, en als er een vol is ontvangt mijn applicatie een message MM_WIM_DATA. Op dat moment voeg ik een nieuwe buffer toe, en lees ik de oude uit.

Nou wil ik controleren of de volle buffer ook de eerst aangevoerde buffer is, vooral om debugging redenen. Volgens de MSDN documentatie bevat de MM_WIM_DATA message een double lParam, met daarin de pointer naar de buffer. Deze wil ik dus vergelijken met de pointer naar de oudst bestaande buffer. De buffers zijn gepinned in het geheugen.

Het probleem is dat die vergelijking nooit uitkomt. Ik zal wel iets triviaal fout doen, maar ik weet niet hoe het dan wel moet. Kan iemand me op weg helpen?

Relevante codeknipsels:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public void handleData(Message m)
{
          // Get the olderst buffer
          Buffer buf = buffers[0];
          Console.WriteLine(buf.ptr == m.LParam); // geeft false
}

private class Buffer : IDisposable
{
            private WinAudio.WAVEHDR wihdr;
            private GCHandle hwihdr;

            public Buffer(IntPtr hin, int bts, int size, int chnnls)
            {
                wihdr = new WinAudio.WAVEHDR();
                hwihdr = GCHandle.Alloc(wihdr, GCHandleType.Pinned);

                WinAudio.waveInPrepareHeader(hwavein, ref wihdr, Marshal.SizeOf(wihdr));
                WinAudio.waveInAddBuffer(hwavein, ref wihdr, Marshal.SizeOf(wihdr));
            }

            public IntPtr ptr
            {
                get
                {
                    return (IntPtr)hwihdr;
                }
            }
}

TabCinema : NiftySplit


Acties:
  • 0 Henk 'm!

  • CoolGamer
  • Registratie: Mei 2005
  • Laatst online: 06-09 16:59

CoolGamer

What is it? Dragons?

Uit de link die jij geeft: http://msdn.microsoft.com/en-us/library/aa909814.aspx
Pointer to a WAVEHDR structure that identifies the buffer containing the data.
m.LParam.lpData zal waarschijnlijk de plek zijn van de pointers die wel overeen komen.

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


Acties:
  • 0 Henk 'm!

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
lParam heeft geen properties. Als ik buf.ptr laat verwijzen naar wihdr.lpdata krijg ik nog steeds false in de vergelijking.

Nu ik erover nadenk, moet ik m.LParam eigenlijk niet formeel converteren naar een IntPtr ofzo? (is al een IntPtr)

[ Voor 5% gewijzigd door Bozozo op 12-01-2010 20:21 ]

TabCinema : NiftySplit


Acties:
  • 0 Henk 'm!

  • CoolGamer
  • Registratie: Mei 2005
  • Laatst online: 06-09 16:59

CoolGamer

What is it? Dragons?

Misschien is de struct gekopieerd?
Pointer to a WAVEHDR structure that identifies the buffer containing the data.
Als dat het geval is kan het zijn dat het een nieuwe pointer heeft gekregen.

Een andere mogelijke oplossing:
WAVEHDR heeft ook het veld dwUser wat je zelf in kan stellen. Deze zou je dus kunnen gebruiker om een nummer in op te slaan.

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


Acties:
  • 0 Henk 'm!

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
De data staat netjes waar ik het verwacht (in een gepinned stukje geheugen) dus ik denk niet dat de struct id gekopieerd. Het dwUser veld gebruiken is misschien een optie maar lijkt me onhandig.

TabCinema : NiftySplit


Acties:
  • 0 Henk 'm!

  • CoolGamer
  • Registratie: Mei 2005
  • Laatst online: 06-09 16:59

CoolGamer

What is it? Dragons?

De code lijkt mij ook wel in order. Bevat buffers[0] echt het eerste element?

Als je met de debugger kijkt naar zo'n message, waar wijst LParam dan naar toe?

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


Acties:
  • 0 Henk 'm!

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
TheCoolGamer schreef op dinsdag 12 januari 2010 @ 21:08:
De code lijkt mij ook wel in order. Bevat buffers\[0] echt het eerste element?

Als je met de debugger kijkt naar zo'n message, waar wijst LParam dan naar toe?
1. Buffer[0] bevat uiteraard het eerste element van de lijst, en ook de oudste buffer. De vraag is of de binnenkomende message naar dezelfde buffer verwijst.

2. LParam is een pointer... ik kan niet zomaar zien waar die naar verwijst. Ik heb geprobeerd LParam om te zetten naar een WAVHDR struct met Marshal.PtrToStructure maar dat gaf een error.

TabCinema : NiftySplit


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Als het goed is kun je met unsafe code gewoon een pointer dereference doen en dan kijken wat het is. Dit zou ik niet zo in Release doen maar als je enkel om debug reden wil weten wat erin zit dan kun je dat zo doen.

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Je hoeft toch niet te Marshallen, want je zit waarschijnlijk toch al in unsafe code? Dus iets als ((WAVEHDR*) m.LParam)->lpData zou genoeg moeten zijn om een referentie naar je buffer te krijgen. Maar als je je eigen WAVEHDR gewoon terugkrijgt, zou je ook die moeten kunnen vergelijken (ligt aan de werking van de WinAudio of WAVEHDR hergebruikt wordt, of gekopieerd).

Het lijkt erop dat je een GCHandle met een WAVEHDR-pointer probeert te vergelijken. GCHandle casten naar een IntPtr roept GCHandle.ToIntPtr() aan op die GCHandle, wat niet hetzelfde geeft als .AddrOfPinnedObject(). Daarnaast gebruik je .AddrOfPinnedObject() ook niet bij het aanroepen van WinAudio, dus vergelijken zal nog steeds erg lastig zijn. Mijn vermoeden is eigenlijk dat je huidige code de mist in gaat als de garbage collector aan het werk gaat en dingen verplaatst, of dat dat Pinned geheugen voor de header niet nodig is, en alleen voor de daadwerkelijke buffer nodig is, maar ik weet niet het fijne van de libraries die je gebruikt.. Een optie is trouwens ook om Microsoft's voorbeeld te gebruiken. ;)

Ik vraag me trouwens ook af wat die new WAVEHDR() moet doen, aangezien WAVEHDR() waarschijnlijk een struct is. ;) Wat wel logische code is, is als je geen kopie van een oude WAVEHDR opslaat, maar daar "new WAVEHDR()" gebruikt. Vervolgens kun je "ref *(WAVEHDR*)hwihdr.AddrOfPinnedObject()" gebruiken om de boel door te geven, of je past de declaraties in WinAudio iets aan zodat daar IntPtr staat ipv ref WAVEHDR. Verder kun je als het goed is gewoon sizeof(WAVEHDR) gebruiken, als daarvan de attributen goed staan.

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Ik heb nu een werkend stukje code gefabriekseld:

C#:
1
WinAudio.WAVEHDR wh = (WinAudio.WAVEHDR)Marshal.PtrToStructure(m.LParam, typeof(WinAudio.WAVEHDR));


Daarmee kan ik in elk geval debuggen. Het blijkt dat buffer[0] steeds de goede buffer teruggeeft.

Marshallen is voor in de Release te onhandig, dus ik ga ook even naar de ideeën van Pedorus kijken.

TabCinema : NiftySplit


Acties:
  • 0 Henk 'm!

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Hmm, het is me niet gelukt om iets nuttigs te doen met unsafe code.

Ik hoef het probleem gelukkig niet meer op te lossen want debuggen wijst uit dat ik altijd netjes de oudste buffer terugkrijg. Soms is deze niet netjes gevuld, maar dan kan ik hem gewoon weggooien en verder gaan.

Toch bedankt voor de moeite :)

TabCinema : NiftySplit


Acties:
  • 0 Henk 'm!

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Aaaargh ik word helemaal gek!

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
WinAudio.WAVEHDR wh = (WinAudio.WAVEHDR)Marshal.PtrToStructure(m.LParam, typeof(WinAudio.WAVEHDR));
Console.WriteLine("Done flag:               " + (wh.dwFlags & WinAudio.WHDR_DONE));
Console.WriteLine("Oldest buffer done:      " + (buf.complete));
Console.WriteLine("Points to expected data: " + (buf.lpData == wh.lpData));

//Met in de Buffer class o.a.:
public bool complete
{
  get {
    return (wihdr.dwFlags & WinAudio.WHDR_DONE) == 1;
  }
}
public IntPtr lpData
{
  get
  {
    return wihdr.lpData;
  }
}


Dit geeft (zeer incidenteel) de output:
code:
1
2
3
Done flag:               1
Oldest buffer done:      False //(dit is in 99% van de gevallen dus true, maar af en toe niet)
Points to expected data: True


In het Nederlands:
1. Ik maak een header. Voor de data wordt een stuk geheugen gereserveerd (en gepinned), waarnaar wordt verwezen in het veld wihdr.lpData
2. Er komt een header binnen. Deze kan ik Marshallen naar een nieuw header object. Die nieuwe header heeft de status Done. De data van de nieuwe header staat op het adres de eerder verzonden header, zoals blijkt uit de vergelijking tussen de lpData pointers. Echter, deze oude header heeft soms niet de status Done (maar InQueue).

WTF?

[ Voor 6% gewijzigd door Bozozo op 13-01-2010 17:37 ]

TabCinema : NiftySplit


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Wat is dwBytesRecorded in zo'n geval? Bovendien:
The MM_WIM_DATA message is sent to a window when waveform-audio data is present in the input buffer and the buffer is being returned to the application. The message can be sent either when the buffer is full or after the waveInReset function is called.
Roep je toevallig ergens waveInReset() aan?

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
buf.wihdr.dwBytesRecorded is 0
wh.dwBytesRecorded is 4096 (het aantal elementen)

waveInReset roep ik pas aan als op de stopknop wordt gedrukt, niet tijdens het loopen.

edit: ergens is het natuurlijk ook gewoon niet netjes wat ik doe. Ik gebruik een object in C# terwijl Windows nog in dat object kan zitten te schrijven. Tijdens het debuggen kreeg ik bijvoorbeeld dit:
C#:
1
2
3
4
                if (!buf.complete)
                {
O                  Console.WriteLine("Buffer complete: " + buf.complete);   //hier staat dus een breakpoint
                }

Als ik aankom op dat breakpoint en ik bekijk buf.complete dan is die inmiddels true geworden :P

[ Voor 59% gewijzigd door Bozozo op 13-01-2010 20:47 ]

TabCinema : NiftySplit

Pagina: 1