e
About me| Chi sono?| BLOG
Chiara| Paola| Valentina| Francesca
Home| Download| Poesie | Poems| Immagini | Pictures| Articoli | Papers| Winamp Plugins
English
› Home » Download › Poems › Pictures › Technical Papers › Winamp Plugins
Italiano
› Principale » Download › Poesie › Immagini › Articoli IoProgrammo › Plugins per Winamp

NoCDSvc Windows Service Assembly (Assembler) Source Code - Win32Asm (MASM32)

Back to the Download Page
Torna alla Sezione Download


; 12-Marzo-2004 - Salvatore Meschini - http://smeschini.altervista.org
; NoCDSvc - Un Windows Service utile per i programmatori distratti che spesso dimenticano un cd
; importante nel lettore cd... Con questo piccolo servizio (l'eseguibile occupa solo 1664 byte!!!)
; scritto in Macro Assembler (MASM32) non capiterà più! :-)
; Su uno dei prossimi numeri di IoProgrammo verrà presentato un articolo che mostrerà come implementare Windows Service
; in C# (.NET Framework)... tutta un'altra storia! :-)))
; Sezione INCLUDE - Modifica i percorsi se necessario include d:\masm32\include\windows.inc include d:\masm32\include\kernel32.inc include d:\masm32\include\advapi32.inc include d:\masm32\include\user32.inc include d:\masm32\include\winmm.inc ; Sezione LIBRERIE - Modifica i percorsi se necessario includelib d:\masm32\lib\kernel32.lib includelib d:\masm32\lib\advapi32.lib includelib d:\masm32\lib\user32.lib includelib d:\masm32\lib\winmm.lib ; Sezione Prototipi ServizioNoCD PROTO stdcall :DWORD, :DWORD Termina PROTO stdcall :DWORD MostraErrore PROTO stdcall :DWORD ; Viene richiamata diverse volte, usiamo una macro! Grazie MASM! CARICA MACRO dest, src mov eax, src mov dest, eax ENDM ; Variabili e costanti .data ; Nome del servizio NOME_SERVIZIO BYTE "NoCdSvc",0 ; Stato del servizio SonoVivo HANDLE NULL MESSAGGIO_ERRORE db "Esegui il programma INSTALLA!",0 ; Dati non inizializzati .data? Stato DWORD ? Stato_Servizio SERVICE_STATUS <> ; Tabelle usate dal servizio Tabella SERVICE_TABLE_ENTRY < 0, 0 > Tabella2 SERVICE_TABLE_ENTRY < 0, 0 > ; Inizia il codice! .code start: ; Registrazione tramite SCM mov Tabella.lpServiceProc, offset ServizioNoCD CARICA Tabella.lpServiceName, offset NOME_SERVIZIO INVOKE StartServiceCtrlDispatcher, ADDR Tabella ; Tutto ok? .IF eax == 0 INVOKE MostraErrore, ADDR MESSAGGIO_ERRORE .ENDIF ; Termina INVOKE ExitProcess, eax ; Inizializzazione del servizio Init proc ; Gestisci eventualmente command-line e poni in eax 1 se tutto ok, 0 se errore mov eax, 1 ret Init endp ; Ferma il servizio Stop proc INVOKE SetEvent, SonoVivo ret Stop endp ; Crea una stringa partendo da Contatore parametri Concatena proc C Contatore:DWORD,lpBuffer:DWORD,args:VARARG push esi push edi mov edi,lpBuffer xor ecx,ecx lea edx,args dec edi @@: inc edi mov al,[edi] or al,al jne @B nuova: dec edi mov esi,[edx][ecx*4] @@: inc edi mov al,[esi] mov [edi],al inc esi or al,al jne @B inc ecx cmp ecx,Contatore jne nuova pop edi pop esi ret Concatena endp Aprilo proc Lettera:DWORD ; Apri il cassetto del lettore CD (SE E SOLO SE un cd inserito) LOCAL Buffer[6]:BYTE ; Vero/Falso LOCAL Comando[256]:BYTE ; Buffer comando jmp @F ; Ho bisogno di alcune "variabili locali" :-) ; Comandi MCI Apri db 'open ',0 CdAudio db ' type cdaudio alias corrente wait',0 ; Usa l'alias CORRENTE Espulsione db 'set corrente door open',0 ChiusuraDispositivo db 'close corrente',0 Presente db 'status corrente media present',0 CDPresente db 'true',0 ; Esito positivo (usato nel confronto) @@: INVOKE Concatena, 3, ADDR Comando, ADDR Apri, Lettera, ADDR CdAudio ; Crea il comando INVOKE mciSendString,ADDR Comando,0,0,0 ; Apri dispositivo INVOKE mciSendString,ADDR Presente,ADDR Buffer,sizeof Buffer,0 INVOKE lstrcmp,addr Buffer,offset CDPresente ; Tutto ok? .IF eax == 0 ; Eax = 0 ==> Il cd inserito nel lettore INVOKE mciSendString,ADDR Espulsione,0,0,0 ; Fuori! .ENDIF INVOKE mciSendString,ADDR ChiusuraDispositivo,0,0,0 ; Comportati bene... mov Comando, 0 ; Resetta il Comando per l'eventuale lettore successivo ret Aprilo endp ApriLettori proc ; Esegue una scansione dei drive ed invoca la proc Aprilo LOCAL DRIVES[106]:BYTE INVOKE GetLogicalDriveStrings, sizeof DRIVES, ADDR DRIVES lea esi, DRIVES ; ESI punta al primo drive (A:\) (si potrebbe partire dal terzo...) mov ecx,eax ; ECX = lunghezza della risposta .WHILE ecx > 0 ; Scansione del risultato (DRIVES) lea ebx, [esi] push ecx ; GetDriveType modifica ECX INVOKE GetDriveType, ebx ; Tipo drive .IF eax == DRIVE_CDROM INVOKE Aprilo, ebx .ENDIF pop ecx ; Riprista il valore del contatore add esi, 4 ; Passa al drive successivo sub ecx, 4 ; Decrementa il contatore .ENDW ret ApriLettori endp ; Gestisci eventuali errori MostraErrore proc Errore:DWORD INVOKE MessageBoxA, NULL, ADDR MESSAGGIO_ERRORE, ADDR NOME_SERVIZIO, MB_OK or MB_ICONERROR INVOKE ExitProcess, Errore ret MostraErrore endp ; Invia lo stato al controllore InviaStato proc dwStatoCorrente:DWORD, dwWin32ExitCode:DWORD, dwServiceSpecificExitCode:DWORD, dwCheckPoint:DWORD, dwWaitHint:DWORD ; Imposto i dati relativi allo stato: mov Stato_Servizio.dwServiceType, SERVICE_WIN32_OWN_PROCESS CARICA Stato_Servizio.dwCurrentState, dwStatoCorrente .IF dwStatoCorrente == SERVICE_START_PENDING mov Stato_Servizio.dwControlsAccepted, 0 .ELSE mov Stato_Servizio.dwControlsAccepted, SERVICE_ACCEPT_STOP or SERVICE_ACCEPT_SHUTDOWN .ENDIF .IF dwServiceSpecificExitCode == 0 CARICA Stato_Servizio.dwWin32ExitCode, dwWin32ExitCode .ELSE mov Stato_Servizio.dwWin32ExitCode, ERROR_SERVICE_SPECIFIC_ERROR .ENDIF CARICA Stato_Servizio.dwServiceSpecificExitCode, dwServiceSpecificExitCode CARICA Stato_Servizio.dwCheckPoint, dwCheckPoint CARICA Stato_Servizio.dwWaitHint, dwWaitHint ; Dopo aver caricato i dati nella struttura imposta lo stato del servizio: INVOKE SetServiceStatus, Stato, ADDR Stato_Servizio mov eax, 1 ; Questa procedure potrebbe essere migliorata con la gestione degli eventi PAUSE/RESUME ; In tal caso bisogna aggiungere altri controlli al campo Stato_Servizio.dwControlsAccepted ret InviaStato endp ; Comunica con SCM GestisciControllo proc Comando:DWORD LOCAL StatoCorrente:DWORD mov StatoCorrente, 0 mov eax, Comando ; Comando ricevuto ; Gestione comando: .IF eax == SERVICE_CONTROL_STOP CARICA StatoCorrente, SERVICE_STOP_PENDING INVOKE InviaStato, SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000 call Stop ret .ELSEIF eax == SERVICE_CONTROL_INTERROGATE ; Interrogazione: TODO .ELSEIF eax == SERVICE_CONTROL_SHUTDOWN ; SHUTDOWN! Non difficile estendere il servizio per gestire pi lettori CD... call ApriLettori ; Apre se necessario i vari lettori... ret .ENDIF ; Invia lo StatoCorrente INVOKE InviaStato, StatoCorrente, NO_ERROR, 0, 0, 0 ret GestisciControllo endp ; Termina il processo Termina proc Errore:DWORD .IF SonoVivo != 0 ; SonoVivo? push SonoVivo call CloseHandle ; Ora non pi ... :-) .ENDIF .IF Stato != 0 INVOKE InviaStato, SERVICE_STOPPED, Errore, 0, 0, 0 .ENDIF Termina endp ; Routine MAIN (registrata nella sezione .code, etichetta start) ServizioNoCD proc argc:DWORD, argv:DWORD ; Registra il servizio INVOKE RegisterServiceCtrlHandler, ADDR NOME_SERVIZIO, GestisciControllo mov Stato, eax .IF eax == 0 ; Errore? call GetLastError push eax call Termina ret .ENDIF ; Comunica con SCM INVOKE InviaStato, SERVICE_START_PENDING, NO_ERROR, 0, 1, 5000 INVOKE CreateEvent, 0, TRUE, FALSE, 0 mov SonoVivo, eax ; Serve per mantenere "in vita" il servizio, vedi WaitForSingleObject .IF eax == 0 ; Errore? call GetLastError push eax call Termina ret .ENDIF ; Comunica con SCM INVOKE InviaStato, SERVICE_START_PENDING, NO_ERROR, 0, 2, 1000 INVOKE InviaStato, SERVICE_START_PENDING, NO_ERROR, 0, 3, 5000 ; Avvia il servizio call Init .IF eax == 0 call GetLastError push eax call Termina ret .ENDIF INVOKE InviaStato, SERVICE_RUNNING, NO_ERROR, 0, 0, 0 ; Mantieni in vita il servizio mediante l'evento SonoVivo INVOKE WaitForSingleObject, SonoVivo, INFINITE push 0 call Termina ; Termina il servizio ret ServizioNoCD endp end start ; That's all folks! :-) SAL