Toon posts:

[c#] Adres van een struct verkrijgen

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik wil graag een methode maken die een struct als parameter krijgt.
In die methode wil ik het adres en de grootte te weten komen omdat ik
die nodig heb om een Win32 API aanroep te doen die die gegevens nodig heeft.
Het kan echter alleen elke keer een ander type struct zijn die als parameter
door gegeven wordt.

Als je een instantie van een klasse wil doorgeven aan een methode en je weet het type nog niet van te voren, dan gebruik je als parameter type Object.
Bij een struct dacht ik dan ValueType.
Je kan echter niet het adres opvragen van een instantie van ValueType.

Een ander idee was om de parameter door een fixed block te laten voeren.
Ook dan komt de compiler met de foutmelding dat hij geen adres van een managed
type kan opvragen.

Het opvragen van een adres staat trouwens altijd binnen een unsafe block.

Het volgende probeerde ik te bereiken:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void CapiPutMessage(ValueType message)
{
    uint pMessage = 0;
            
    unsafe 
    {
        pMessage = (uint)&message; 
    }

    uint retValue = CAPI_PUT_MESSAGE(capiAppId, pMessage);

    if (retValue != 0) 
    {
        throw new ApplicationException("CapiPutMessage ErrorCode: " + retValue);
    }
}


Ik wil als parameter gewoon een instantie van een struct meegeven zodat ik in
de aanroepende code geen unsafe code hoef te gebruiken.

Heeft iemand een idee hoe ik dit voor elkaar ga krijgen?

Verwijderd

Ik ben geen OO programmeur en C# ken ik helemaal niet, maar in standaard C krijg je het adres van een struct door een '&' voor de variabele naam te zetten. De grootte krijg je met behulp van 'sizeof'.
code:
1
2
3
4
5
6
7
// struct definitie
struct ABC
{
  char a;
  short b;
  int c;
};


code:
1
2
3
4
5
6
7
8
9
10
11
12
// declaratie
struct ABC myvariable
struct ABC *ptr;
int size;

  ptr=&myvariable;                // ptr bevat nu adres van myvariable
  size=sizeof(myvariable);        // size bevat de grootte van myvariable

  // een functie die adres en grootte meekrijgt
  myfunc(ptr,size);
  // of
  myfunc(&myvariable,sizeof(myvariable));


Ik hoop dat dit je op weg helpt.

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:02
SizeOf kan je in C# nog doen, maar dat is wel 'unsafe' code. Als je die gebruikt moet je die code dus in een 'unsafe'-block zetten.

https://fgheysels.github.io/


Verwijderd

Topicstarter
Ik gebruik al een & operator en hij staat binnen een unsafe block zoals ik in het voorbeeld liet zien. Het probleem is dat je die operatoren niet mag gebruiken op unmanaged types.

Maar ik snap niet dat ik bijvoorbeeld geen sizeof mag doen van een afgeleide van ValueType.
Als dat mocht was mijn probleem opgelost.
Een ValueType staat toch altijd op de stack, dan is het toch geen probleem?

Volgens mij heeft bill een beetje zitten slapen.. :)

[ Voor 8% gewijzigd door Verwijderd op 26-03-2003 09:14 ]


  • EfBe
  • Registratie: Januari 2000
  • Niet online
waarom gebruik je geen class? Een struct is een valuetype en normaliter pass je die by value naar methods.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Verwijderd

Topicstarter
Omdat ik alleen een struct kan gebruiken om die win32 api aan te roepen.
Struct staan op de stack in tegenstelling tot klassen die op de heap staan.
En je kan alleen een adres opgvragen van een value op de heap.
Dat adres moet je doorgeven aan de API call. Tevens kan je alleen van een struct de layout bepalen...

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Huh? Elke aanroep van een Win32 api verwacht bij een C-Struct een adres van die struct. Dus t.a.t. kun je daar een adres van een C-struct opgeven (die overigens geen valuetypes zijn). Welke api call wil je doen dan?

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Verwijderd

Je moet de allignment van de struct expliciet maken met het "ExplicitLayout" attribute dan zou SizeOf( object ) moeten werken.....

Voor de exacte syntax zal je even bij de MSDN libs moeten kijken....

[ Voor 26% gewijzigd door Verwijderd op 26-03-2003 23:30 ]


Verwijderd

Topicstarter
Efbe, in c# is een struct wel een ValueType en ik moet c# structs gebruiken. Het adres opvragen van mijn structs is geen probleem als ik alles in 1 methode doe. Ik wil echter het struct in een andere methode aanmaken en die doorgeven. Daarna wil ik pas het adres opvragen en dat is wel een probleem. Ik wil trouwens de CAPI drivers aanroepen om nummer herkenning te doen. Dat werkt al, maar ik wil mijn code wat opschonen...

5371, ik gebruik "[StructLayout(LayoutKind.Sequential)]" en dat werkt goed.
Het probleem zit hem ook niet in de aanroep van de API, maar in de c# code, die een struct niet meer herkent als een struct als die is doorgegeven aan een methode die een ValueType verwacht. Je kan die referentie/value niet naar iets casten dat je het adres ervan op kan vragen.
Tenminste niet zover ik weet.....

Verwijderd

Ik ben bang dat het in C# niet gaat lukken... wellicht kun je in managed C++ wel iets doen....

  • kenneth
  • Registratie: September 2001
  • Niet online

kenneth

achter de duinen

Dit is toch het geweldige .NET ?? Dan lijkt het me interessant om 5371's wat een nick :P idee te proberen. Juist met .NET hoef je je niet meer vast te binden aan een taal.

Look, runners deal in discomfort. After you get past a certain point, that’s all there really is. There is no finesse here.


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:02
Verwijderd schreef op 27 March 2003 @ 17:09:
Ik ben bang dat het in C# niet gaat lukken... wellicht kun je in managed C++ wel iets doen....


Kan je ook onderbouwen waarom het in C# niet zal lukken en in managed C++ wel?

https://fgheysels.github.io/


Verwijderd

Topicstarter
Volgens mij heb ik een oplossing gevonden.
Ik ben er alleen nog niet echt blij mee aangezien hij de struct moet copieren en daardoor dus performance verlies heeft...

De oplossing:

C#:
1
2
3
4
5
6
7
8
public static unsafe void pass(object p) 
{
    byte* pb = stackalloc byte[Marshal.SizeOf(p)];
    Marshal.StructureToPtr(p, new IntPtr(pb), false);
            
    uint address = (uint)pb;
    // Do something with it
}


Dus eerst een nieuwe buffer op de stack alloceren en vervolgens de struct copieren
naar de nieuwe buffer met Marshal.StuctureToPtr();

Opent dit nieuwe inzichten om het misschien voor elkaar te krijgen zonder een copy?
Pagina: 1