[Windows/C] RegisterServiceProcess

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • SWfreak
  • Registratie: Juni 2001
  • Niet online
Ik heb mijn app onder Windows 9x al helemaal aan de praat als service, dwz hij start netjes op als Windows opstart en sluit netjes af als Windows klaar is. Er is echter 1 probleem, nl als de gebruiker uitlogt dan sluit mijn programma ook. Dat is natuurlijk niet de bedoeling van een service. Volgens MSDN gebruik je dan de functie RegisterServiceProcess om te zorgen dat ook na het uitloggen het programma nog draait. Hiertoe heb ik de volgende code geschreven:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//declaraties en definities
HMODULE hKernel;
typedef DWORD (*PFNRSP) (DWORD, DWORD);
PFNRSP pfnRSP;

//de echte code
hKernel = LoadLibrary( "kernel32.dll" );
if( hKernel != NULL )
{
    pfnRSP = (PFNRSP) GetProcAddress( hKernel, "RegisterServiceProcess" );
    if( pfnRSP != NULL )
    {
        if( pfnRSP(GetCurrentProcessId(), 1) )
            registeredSP = TRUE;
    }
    FreeLibrary( hKernel );
}

Dit gaat prima tijdens het opstarten, registeredSP staat keurig op TRUE zoals het hoort. Echter als ik nu Windows afsluit of de service tussentijds afsluit, dan krijg ik de volgende foutmelding:
code:
1
2
3
4
5
6
Microsoft Visual C++ Runtime Library
Buffer overrun detected!
Program: <programmanaam>
A buffer overrun has been detected which has corrupted the program's 
internal state. The program cannot safely continue execution and must 
now be terminated.

Ik heb ff gekeken, en deze foutmelding verschijnt pas helemaal aan het eind. Mijn code daar is:
C:
1
2
3
4
5
6
7
8
9
10
//message loop
while( GetMessage(&msg, NULL, 0, 0) )
{
    TranslateMessage( &msg );
    DispatchMessage( &msg );
}

MessageBox(NULL,"","",0);

return (int) msg.wParam;

Ik zie dus eerst de Messagebox, en daarna komt pas de foutmelding. Je zou denken dat het er aan ligt dat ik de RegisterServiceProcess(GetCurrentProcessId(), 0) oversla en dat het daardoor niet werkt, maar ik krijg ook met die unregister nog de foutmelding. Het moet trouwens wel aan die RegisterServiceProcess liggen, want als ik het hele stuk code eruit haal zijn er geen problemen. Heeft iemand een idee wat hier mis gaat?

Edit: Laat ik er maar ff bijzetten dat ik al op Google en MSDN heb gezocht, maar niets nuttigs gevonden heb.

[ Voor 5% gewijzigd door SWfreak op 30-05-2003 20:33 . Reden: more P&W beleid compliance ]


Acties:
  • 0 Henk 'm!

Verwijderd

FreeLibrary( hKernel );

Wat doet die regel daar?
Kernel32.dll zou ik niet free'en, als je nog andere functies gebruikt die in de kernel32 systeem dll zitten (en die ik kans is vrij groot).

Het enige wat RegisterServiceProcess concreet doet is dat hij niet in het lijstje terecht komt van task manager.

[ Voor 26% gewijzigd door Verwijderd op 31-05-2003 16:36 . Reden: extra info ]


Acties:
  • 0 Henk 'm!

  • SWfreak
  • Registratie: Juni 2001
  • Niet online
Verwijderd schreef op 31 May 2003 @ 16:34:
FreeLibrary( hKernel );

Wat doet die regel daar?
Kernel32.dll zou ik niet free'en, als je nog andere functies gebruikt die in de kernel32 systeem dll zitten (en die ik kans is vrij groot).
Dat kan prima lijkt me, en wel om twee redenen:
a) ik verkrijg alleen maar een dynamische handle naar kernel32.dll. Die heb ik speciaal nodig voor RegisterServiceProcess, omdat die niet onder alle Windows OS-en wordt ondersteunt. Alle andere functies worden gewoon statisch geinclude (of iig op een dusdanige manier dat ik die handle daar niet voor nodig heb.
b) Het probleem treedt pas op bij het afsluiten. Ik kan de applicatie zonder problemen 2 uur laten draaien, allerlei Windows calls laten doen en no problemos.
Ik het nu aangepast zodat ik die FreeLibrary alleen nog maar aan het einde van mijn programma doe en vreemd genoeg/gelukkig heb ik nu geen problemen meer bij het afsluiten van Windows. Alleen als ik tussendoor de service afsluit krijg ik de foutmelding. Aangezien het best wel belangrijk is voor mijn applicatie dat ie tussentijds afgesloten kan worden, ben ik best wel nieuwsgierig.
Het enige wat RegisterServiceProcess concreet doet is dat hij niet in het lijstje terecht komt van task manager.
In ieder geval volgens Microsoft doet RegisterServiceProcess nog wel meer.
A Win32-based application can prevent itself or any other Win32-based application from being closed when the user logs off by calling RegisterServiceProcess(). Win32-based applications registered in this manner close only when the system is shut down.
Nou houdt Microsoft zich wel vaker niet aan haar omschrijvingen, maar RegisterServiceProcess is toch een redelijk bekende functie die kennelijk vaak haar werk zonder problemen doet. Ik zou niet weten waarom nu niet.

[ Voor 7% gewijzigd door SWfreak op 31-05-2003 18:18 . Reden: ff wat onzin weggehaald ]


Acties:
  • 0 Henk 'm!

Verwijderd

SWfreak schreef op 31 mei 2003 @ 18:00:
[...]

Dat kan prima lijkt me, en wel om twee redenen:
a) ik verkrijg alleen maar een dynamische handle naar kernel32.dll. Die heb ik speciaal nodig voor RegisterServiceProcess, omdat die niet onder alle Windows OS-en wordt ondersteunt. Alle andere functies worden gewoon statisch geinclude (of iig op een dusdanige manier dat ik die handle daar niet voor nodig heb.
Je krijgt geen dynamische handle. Er wordt door Windows een reference count op applicatie basis bijgehouden.

LoadLibrary
"The LoadLibrary function maps the specified executable module into the address space of the calling process."

Freelibrary
"Each process maintains a reference count for each loaded library module. This reference count is incremented each time LoadLibrary is called and is decremented each time FreeLibrary is called. A DLL module loaded at process initialization due to load-time dynamic linking has a reference count of one. This count is incremented if the same module is loaded by a call to LoadLibrary."

Maar ja, dan nog verklaart dit nog steeds het probleem niet.
b) Het probleem treedt pas op bij het afsluiten. Ik kan de applicatie zonder problemen 2 uur laten draaien, allerlei Windows calls laten doen en no problemos.
Ik het nu aangepast zodat ik die FreeLibrary alleen nog maar aan het einde van mijn programma doe en vreemd genoeg/gelukkig heb ik nu geen problemen meer bij het afsluiten van Windows. Alleen als ik tussendoor de service afsluit krijg ik de foutmelding. Aangezien het best wel belangrijk is voor mijn applicatie dat ie tussentijds afgesloten kan worden, ben ik best wel nieuwsgierig.

[...]

In ieder geval volgens Microsoft doet RegisterServiceProcess nog wel meer.

[...]

Nou houdt Microsoft zich wel vaker niet aan haar omschrijvingen, maar RegisterServiceProcess is toch een redelijk bekende functie die kennelijk vaak haar werk zonder problemen doet. Ik zou niet weten waarom nu niet.
Hier kan ik niets over zeggen. Het was maar even kort door de bocht een ruime omschrijving van RegisterServiceProcess.


Er schiet me net iets te binnen...
Maakt je applicatie gebruik van een grafische gebruikers interface, dan zou dat eventueel kunnen verklaren dat je applicatie afgesloten wordt bij het uitloggen onder Win9x (en Win2k/XP)

Acties:
  • 0 Henk 'm!

  • SWfreak
  • Registratie: Juni 2001
  • Niet online
Verwijderd schreef op 31 May 2003 @ 18:38:
Je krijgt geen dynamische handle. Er wordt door Windows een reference count op applicatie basis bijgehouden.

LoadLibrary
"The LoadLibrary function maps the specified executable module into the address space of the calling process."

Freelibrary
"Each process maintains a reference count for each loaded library module. This reference count is incremented each time LoadLibrary is called and is decremented each time FreeLibrary is called. A DLL module loaded at process initialization due to load-time dynamic linking has a reference count of one. This count is incremented if the same module is loaded by a call to LoadLibrary."

Maar ja, dan nog verklaart dit nog steeds het probleem niet.
Idd, maar je bent dan hoop ik aan met me eens dat het niet aan die FreeLibrary call mag liggen. Bij het opstarten krijgt ie count 1. LoadLibrary verhoogt naar 2 en FreeLibrary verlaagt dan weer naar 1. Zou dus niet uit moeten maken. Maar goed, het verklaart idd het probleem niet.
Er schiet me net iets te binnen...
Maakt je applicatie gebruik van een grafische gebruikers interface, dan zou dat eventueel kunnen verklaren dat je applicatie afgesloten wordt bij het uitloggen onder Win9x (en Win2k/XP)
Ik heb het zowel getest voor een applicatie met en zonder grafische interface. Dat ie afgesloten zou worden bij uitloggen had ik ook wel verwacht. Maar mijn huidige code bij WM_ENDSESSION is dusdanig dat ie niet afsluit bij uitloggen, maar Windows zal zonder die call naar RegisterServiceProcess mijn app gewoon hard afsluiten, dus daarom heb ik m per se nodig.

Acties:
  • 0 Henk 'm!

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Gebruikt je programma niet nog functies van de kernel32.dll nadat je m gefreed hebt?

We adore chaos because we like to restore order - M.C. Escher


Acties:
  • 0 Henk 'm!

  • SWfreak
  • Registratie: Juni 2001
  • Niet online
LordLarry schreef op 31 May 2003 @ 20:03:
Gebruikt je programma niet nog functies van de kernel32.dll nadat je m gefreed hebt?
Oh vast wel, maar inmiddels free ik hem niet meer (ookal zou het theoretisch niets uit moeten maken). Maar ondanks dat ik die free weggelaten heb, krijg ik nog steeds de buffer overrun.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 12-09 15:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

Die FreeLibrary () is zelfs verplicht (als je netjes wilt coden iig, hij zal uiteindelijk toch wel gefreed worden als de applicatie afsluit ;)), sinaasappel haalde dit al aan. Voor elke LoadLibrary () moet een FreeLibrary () aangeroepen worden. De module wordt alleen vrijgegeven als er geen references meer naar zijn, en dus kan dit geen probleem geven.

Wat je probleem echter wel is is dat winapi functies altijd stdcall zijn. In C zijn je functies standaard cdecl. Een stdcall functie ruimt z'n eigen stack op, bij een cdecl functie moet de caller dat doen.

Het resultaat is dat de functie die je aanroept (RegisterServerProcess) z'n stack opruimt, en jouw code doet dat nog eens omdat de compiler denkt dat het een cdecl functie is. Resultaat: stack corrupt.

Je moet PFNRSP dus zo declareren:
C:
1
DWORD (__stdcall * PFNRSP) (DWORD, DWORD);

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!

  • SWfreak
  • Registratie: Juni 2001
  • Niet online
|:( Stom, ja dat was 'm. Ik had al een minimaal testprogrammaatje gebrouwen en dat door de debugger heen gehaald en daar zei ie inderdaad dat er iets mis ging met calling conventions. Wist niet precies wat, wilde het vragen, maar het antwoord staat er al :) Thanks .oisyn!
Pagina: 1