DLLCALL under Fivewin

Re: DLLCALL under Fivewin

Postby Antonio Linares » Fri Dec 02, 2022 3:59 pm

Dear Jimmy,

Please post a small and self contained PRG to test it here

many thanks
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: DLLCALL under Fivewin

Postby Jimmy » Fri Dec 02, 2022 5:30 pm

hi Antonio,

here it is
Code: Select all  Expand view
#include "FIVEWIN.ch"
#include "common.ch"

#include "dll.ch"
#include "hbdyn.ch"

#include "EJECTDLL.CH"

#define FILE_SHARE_READ                   0x00000001
#define FILE_SHARE_WRITE                  0x00000002
#define FILE_SHARE_DELETE                 0x00000004
#define FILE_SHARE_VALID_FLAGS            0x00000007

#define GENERIC_READ                      0x80000000
#define GENERIC_WRITE                     0x40000000
#define GENERIC_EXECUTE                   0x20000000
#define GENERIC_ALL                       0x10000000

#define OPEN_EXISTING                     3

#define DRIVE_UNKNOWN         0
#define DRIVE_NO_ROOT_DIR     1
#define DRIVE_REMOVABLE       2
#define DRIVE_FIXED           3
#define DRIVE_REMOTE          4
#define DRIVE_CDROM           5
#define DRIVE_RAMDISK         6

#define SW_SHOW               5

#define DLL_CDECL                   0x08
#define DLL_STDCALL                 0x20
#define DLL_SYSTEM                  0x04
#if defined( __PLATFORM__WINDOWS )
#define DLL_OSAPI                   DLL_STDCALL
#elif defined( __PLATFORM__OS2 )
#define DLL_OSAPI                   DLL_SYSTEM
#else
#define DLL_OSAPI                   DLL_CDECL
#endif


MEMVAR hDLL

*+--------------------------------------------------------------------
*+
*+    Procedure USBeject()
*+
*+    Called from ( dualgrid.prg )   1 - static procedure buildmainmenu()
*+
*+--------------------------------------------------------------------
*+
PROCEDURE USBeject()

LOCAL oDlg, oListbox
LOCAL cDrive  := SPACE( 2 )
LOCAL cTitle  := "Please, select"
LOCAL aDrives := aDrives()

LOCAL bSetGet := {|x| cDrive := x }
LOCAL bChange
LOCAL bValid
LOCAL bLDblClicked
LOCAL bWhen
LOCAL bDrawItem

PRIVATE hDLL

   DEFINE DIALOG oDlg FROM 5, 10 TO 24, 55 TITLE cTitle

      oListbox := TListBox() :New( 10, 20, bSetGet, aDrives, 145, 95, bChange, ;
                             oDlg, bValid, , , .T., .F., ;
                             bLDblClicked, , "", .T., bWhen,, ;
                             bDrawItem, .F., .F. )

      @  7,  7 BUTTON "&OK" OF oDlg SIZE 40, 12 ;
              ACTION( EjectMedia( cDrive ), oDlg:End() ) DEFAULT

      @  7, 17 BUTTON "&Cancel" OF oDlg SIZE 40, 12 ;
              ACTION( cDrive := nil, oDlg:End() )

#IFDEF __HMG__
   END DIALOG
#ENDIF

   ACTIVATE DIALOG oDlg CENTERED

RETURN

*+--------------------------------------------------------------------
*+
*+    Function EjectMedia()
*+
*+    Called from ( hbeject.prg )   1 - procedure usbeject()
*+
*+--------------------------------------------------------------------
*+
FUNCTION EjectMedia( cDrive, UseCDdrives )

   // ***************************************************************
   //
   //  USBeject based on https://support.microsoft.com/en-us/kb/165721
   //
   //  will eject CD / DVD and "flush Buffer" if USB Drive
   //
   // ***************************************************************

LOCAL hVolRead  := - 1 // "CreateFileA"
LOCAL nLock     := 0 // "DeviceIoControl",hVolRead, FSCTL_LOCK_VOLUME
LOCAL nDisMount := 0 // "DeviceIoControl",hVolRead, FSCTL_DISMOUNT_VOLUME
LOCAL nEject    := 0 // "DeviceIoControl",hVolRead, IOCTL_STORAGE_EJECT_MEDIA
LOCAL nAccess   := 0
LOCAL nType     := 0
LOCAL cMsg      := ""
LOCAL nRemove   := 0
LOCAL lRet      := .T.
LOCAL cAction   := GETENV( "SYSTEMROOT" ) + "\SYSTEM32\HOTPLUG.DLL"
LOCAL cRoot     := "RUNDLL32.EXE "
LOCAL cPath     := GETENV( "TEMP" ) + "\"

   DEFAULT UseCDdrives TO .F.

   IF PCOUNT() = 0
      MsgInfo( "
need Drive Letter" )
      RETURN .F.
   ENDIF
   IF EMPTY( cDrive )
      MsgInfo( "
Error no Drive Letter" )
      RETURN .F.
   ELSE
      cDrive := SUBSTR( cDrive, 1, 1 )
   ENDIF

   cAction += "
,HotPlugSafeRemovalDriveNotification "
   cAction += VOLUMENAME( cDrive + "
:\" )
   cAction += "
("
   cAction += cDrive + "
:)"

*  msginfo( cDrive )

   nType := DriveType( cDrive )
   DO CASE
      CASE nType = DRIVE_UNKNOWN
      CASE nType = DRIVE_NO_ROOT_DIR
      CASE nType = DRIVE_REMOVABLE                                    //  Floppy
         nAccess := GENERIC_READ + GENERIC_WRITE
      CASE nType = DRIVE_FIXED
      CASE nType = DRIVE_REMOTE
      CASE nType = DRIVE_CDROM
         IF UseCDdrives = .T.
            nAccess := GENERIC_READ
         ENDIF
      CASE nType = DRIVE_RAMDISK
      OTHERWISE
         MsgInfo( "
can not use Type " + STR( nType ) )
   ENDCASE

   IF EMPTY( nAccess )
      RETURN .F.
   ENDIF

   IF EMPTY(hDll)
       hDll := LoadLibrary( "
Kernel32.dll" )
   ENDIF

   SayInfo( "
waiting for Drive " + cDrive + CRLF )
   hVolRead := CreateVolHandle( @cMsg, nType, nAccess, cDrive )

   IF hVolRead = - 1
      MsgInfo( "
Unable to open drive " + cDrive )
      lRet := .F.
   ELSE

      // *********************************************************
      //
      //  https://msdn.microsoft.com/en-us/library/Aa363216.aspx
      //
      //  BOOL WINAPI DeviceIoControl(
      //    _In_        HANDLE       hDevice,
      //    _In_        DWORD        dwIoControlCode,
      //    _In_opt_    LPVOID       lpInBuffer,
      //    _In_        DWORD        nInBufferSize,
      //    _Out_opt_   LPVOID       lpOutBuffer,
      //    _In_        DWORD        nOutBufferSize,
      //    _Out_opt_   LPDWORD      lpBytesReturned,
      //    _Inout_opt_ LPOVERLAPPED lpOverlapped
      //  );
      //
      // *********************************************************

      nLock := LockVolume( hVolRead )
      IF nLock <> 0
         cMsg := "
LockVolume()" + CRLF
         SayInfo( cMsg )

         nDisMount := DismountVolume( hVolRead )
         IF nDisMount <> 0
            cMsg := "
DismountVolume()" + CRLF
            SayInfo( cMsg )

            // nRemove := PreventRemovalOfVolume( hVolRead, .F. )
            nRemove := 1
            IF nRemove <> 0
               cMsg := "
PreventRemovalOfVolume()" + CRLF
               SayInfo( cMsg )

               nEject := AutoEjectVolume( hVolRead )
               //     IF nEject = 0
               cMsg := "
AutoEjectVolume()" + CRLF
               SayInfo( cMsg )

               //     ELSE
               //         cMsg := "
Error : can not AutoEjectVolume() "+hb_valToExp(nEject))
               //         lRet := .F.
               //     ENDIF
            ELSE
               cMsg := "
Error : can not PreventRemovalOfVolume() " + hb_valToExp( nRemove )
               lRet := .F.
               SayInfo( cMsg )
            ENDIF
         ELSE
            cMsg := "
Error : can not DismountVolume() " + hb_valToExp( nDisMount )
            lRet := .F.
            SayInfo( cMsg )
         ENDIF
      ELSE
         cMsg := "
Error : can not LockVolume() " + hb_valToExp( nLock )
         lRet := .F.
         SayInfo( cMsg )
      ENDIF
   ENDIF

   CloseVolume( hVolRead )

   IF lRet = .F.
      Msginfo( cMsg )
   ELSE
      SayInfo( "
remove your USE-Stick now" )
      hb_IdleSleep( 2.0 )
      IF nType <> DRIVE_CDROM                                  // will eject
         MEMOWRIT( cPath + "
ShowMsg.BAT", cRoot + cAction )
         ShellExecute( 0, "
runas", cPath + "ShowMsg.BAT",,, SW_SHOW )

         hb_IdleSleep( 2.0 )
         FERASE( cPath + "
ShowMsg.BAT" )
      ENDIF
   ENDIF

RETURN lRet

*+--------------------------------------------------------------------
*+
*+    Static Function CreateVolHandle()
*+
*+    Called from ( hbeject.prg )   1 - function ejectmedia()
*+
*+--------------------------------------------------------------------
*+
STATIC FUNCTION CreateVolHandle( cMsg, nType, nAccess, cDrive )

LOCAL hVolWrite
LOCAL hVolRead
LOCAL nFlush    := 0                                                  // "
FlushFileBuffers"
LOCAL cPath     := "
"
LOCAL nShare    := FILE_SHARE_READ + FILE_SHARE_WRITE
LOCAL nDispo    := OPEN_EXISTING
LOCAL nAttrib   := 0 // FILE_FLAG_OVERLAPPED + FILE_FLAG_BACKUP_SEMANTICS

FWLOG "
CreateVolHandle"

   /**********************************************************
   *
   * https://msdn.microsoft.com/en-us/library/aa363858.aspx
   *
   * HANDLE WINAPI CreateFile(
   *   _In_     LPCTSTR               lpFileName,
   *   _In_     DWORD                 dwDesiredAccess,
   *   _In_     DWORD                 dwShareMode,
   *   _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
   *   _In_     DWORD                 dwCreationDisposition,
   *   _In_     DWORD                 dwFlagsAndAttributes,
   *   _In_opt_ HANDLE                hTemplateFile
   * );
   *
   **********************************************************/

   cPath := "
\\.\"
   cPath += cDrive
   cPath += "
:"

   hVolWrite := CreateFile( cPath  , ; // lpFileName
                            nAccess, ; // dwDesiredAccess
                            nShare , ; // dwShareMode
                            NULL   , ; // lpSecurityAttributes
                            nDispo , ; // dwCreationDisposition
                            nAttrib, ; // dwFlagsAndAttributes
                            NULL )     // hTemplateFile

   IF hVolWrite = - 1
      msginfo("
Error hVolWrite = - 1 ")
      RETURN hVolWrite
   ELSE
      // flush buffer
      //
      IF nType <> DRIVE_CDROM
         // Kernel32
         nFlush := FlushFileBuffers( hVolWrite )
         cMsg := "
FlushFile()" + CRLF
      ENDIF
   ENDIF

   CloseHandle(hVolWrite )

   // open again RO
   //
   nAccess := GENERIC_READ

   hVolRead := CreateFile( cPath  , ; // lpFileName
                           nAccess, ; // dwDesiredAccess
                           nShare , ; // dwShareMode
                           NULL   , ; // lpSecurityAttributes
                           nDispo , ; // dwCreationDisposition
                           nAttrib, ; // dwFlagsAndAttributes
                           NULL )     // hTemplateFile
RETURN hVolRead

*+--------------------------------------------------------------------
*+
*+    Static Function LockVolume()
*+
*+    Called from ( hbeject.prg )   1 - function ejectmedia()
*+
*+--------------------------------------------------------------------
*+
STATIC FUNCTION LockVolume( hVolRead )
LOCAL nBytes := 0
LOCAL nLock

   nLock := DeviceIoControl( hVolRead, ;
                     FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, @nBytes, NULL )

RETURN nLock

*+--------------------------------------------------------------------
*+
*+    Static Function DismountVolume()
*+
*+    Called from ( hbeject.prg )   1 - function ejectmedia()
*+
*+--------------------------------------------------------------------
*+
STATIC FUNCTION DismountVolume( hVolRead )
LOCAL nBytes    := 0
LOCAL nDisMount

   nDisMount := DeviceIoControl( hVolRead, ;
                     FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, @nBytes, NULL )
RETURN nDisMount

*+--------------------------------------------------------------------
*+
*+    Static Function AutoEjectVolume()
*+
*+    Called from ( hbeject.prg )   1 - function ejectmedia()
*+
*+--------------------------------------------------------------------
*+
STATIC FUNCTION AutoEjectVolume( hVolRead )
LOCAL nBytes := 0
LOCAL nEject

   nEject := DeviceIoControl( hVolRead, ;
                 IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, @nBytes, NULL )
RETURN nEject

*+--------------------------------------------------------------------
*+
*+    Static Function UnlockVolume()
*+
*+--------------------------------------------------------------------
*+
STATIC FUNCTION UnlockVolume( hVolRead )
LOCAL nBytes  := 0
LOCAL nUnlock

   nUnlock := DeviceIoControl( hVolRead, ;
                       FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, @nBytes, NULL )
RETURN nUnlock

*+--------------------------------------------------------------------
*+
*+    Static Function CloseVolume()
*+
*+    Called from ( hbeject.prg )   1 - function ejectmedia()
*+
*+--------------------------------------------------------------------
*+
STATIC FUNCTION CloseVolume( hVolRead )
LOCAL lClose
   lClose := CloseHandle( hVolRead )
RETURN lClose

*+--------------------------------------------------------------------
*+
*+    Static Function PreventRemovalOfVolume()
*+
*+--------------------------------------------------------------------
*+
STATIC FUNCTION PreventRemovalOfVolume( hVolRead, fPreventRemoval )

LOCAL nBytes  := 0
LOCAL nRemove
LOCAL pmr     := 1                           // PREVENT_MEDIA_REMOVAL():New()
LOCAL nSize   := pmr:_sizeof_()

   pmr:PreventMediaRemoval := fPreventRemoval
   nSize := 1

   nRemove := DeviceIoControl( hVolRead, ;
           IOCTL_STORAGE_MEDIA_REMOVAL, @pmr, nSize, NULL, 0, @nBytes, NULL )

RETURN nRemove

*+--------------------------------------------------------------------
*+
*+    Procedure SayInfo()
*+
*+    Called from ( hbeject.prg )   9 - function ejectmedia()
*+
*+--------------------------------------------------------------------
*+
PROCEDURE SayInfo( cText )

RETURN

* https://learn.microsoft.com/en-us/windo ... reatefilea
DLL FUNCTION CreateFile(lpFileName            AS LPSTR ,;
                        dwDesiredAccess       AS DWORD ,;
                        dwShareMode           AS DWORD ,;
                        lpSecurityAttributes  AS LONG ,;
                        dwCreationDisposition AS DWORD ,;
                        dwFlagsAndAttributes  AS DWORD ,;
                        hTemplateFile         AS LONG ) AS LONG PASCAL FROM "
CreateFileA" LIB hDll

* https://learn.microsoft.com/en-us/windo ... ilebuffers
DLL FUNCTION FlushFileBuffers(hVolWrite       AS LONG) AS LONG PASCAL FROM "
FlushFileBuffers" LIB hDll

* https://learn.microsoft.com/en-us/windo ... losehandle
DLL FUNCTION CloseHandle( hVolRead           AS LONG) AS LONG PASCAL FROM "
CloseHandleA" LIB hDll

* https://learn.microsoft.com/en-us/windo ... eiocontrol
DLL FUNCTION DeviceIoControl( hDevice         AS LONG ,;
                              dwIoControlCode AS DWORD ,;
                              lpInBuffer      AS VOID ,;
                              nInBufferSize   AS DWORD,;
                              lpOutBuffer     AS VOID ,;
                              nOutBufferSize  AS DWORD,;
                              lpBytesReturned AS DWORD,;   // LPDWORD
                              lpOverlapped    AS LPOVERLAPPED ) AS LONG PASCAL FROM "
DeviceIoControl" LIB hDll

*+ EOF: HBEJECT.PRG

use a Drive which IS "removeable" (no Icon show in Demo Sample)

get "EJECTDLL.CH" from this Threa below

thx for help
greeting,
Jimmy
User avatar
Jimmy
 
Posts: 1585
Joined: Thu Sep 05, 2019 5:32 am
Location: Hamburg, Germany

Re: DLLCALL under Fivewin

Postby Antonio Linares » Sat Dec 03, 2022 8:53 am

Dear Jimmy,

I get "Error no Drive Letter" in all cases (I have inserted a USB pendrive)

what to test ? How ?
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: DLLCALL under Fivewin

Postby Enrico Maria Giordano » Sat Dec 03, 2022 9:39 am

Antonio Linares wrote:If it works with HMG then it means there is a #define in FWH that is clashing with a Harbour #define or maybe HMG defines it in a different way

Please review this example to see how easily a new define can replace a previous one, and Harbour does not warn you:
Code: Select all  Expand view
#define TEST 123
#define TEST "Another"

function Main()

   ? TEST

return nil


Code: Select all  Expand view
Warning W0002  Redefinition or duplicate definition of #define TEST


You should work with warnings activated. The correct way is:

#define TEST 123
#undef TEST
#define TEST "Another"

function Main()

? TEST

return nil
User avatar
Enrico Maria Giordano
 
Posts: 8315
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: DLLCALL under Fivewin

Postby Antonio Linares » Sat Dec 03, 2022 9:48 am

Thank you Enrico for the clarification :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: DLLCALL under Fivewin

Postby Jimmy » Mon Dec 05, 2022 3:09 am

hi Antonio,
Antonio Linares wrote:I get "Error no Drive Letter" in all cases (I have inserted a USB pendrive)
what to test ? How ?

you need to press ENTER as i do not know how to use DblClick with Listbox (yet)
it will take some Seconds until it crash

---

i have search and found "Original" CPP Code
perhaps it is better to understand when know CPP
Code: Select all  Expand view
// EjectMediaByLetter.cpp by Uwe Sieber - http://www.uwe-sieber.de
//
// Simple demonstration how to flush, lock and dismount a volume and eject a media from a drive
//
// Works under W2K, XP, W2K3, Vista, Win7, Win8, not tested under Win9x
//
// Console application - expects the drive letter of the drive to eject as parameter
//
// you are free to use this code in your projects
//

#define WIN32_LEAN_AND_MEAN

#include <stdio.h>
#include <windows.h>
#include <winioctl.h>


// returned errorlevels, nice to have when writing documentation later :-)
enum {
    ERRL_SUCCESS = 0,
    ERRL_INVALID_PARAM,
    ERRL_NO_VOLREAD,
    ERRL_NO_LOCK,
    ERRL_NO_EJECT
};


//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
// we expect a single drive letter as param, e.g.
// ejectmediabyletter X
//-------------------------------------------------------------------------------
int main(int argc, char* argv[])
{
    bool ForceEject = false;  // dismount and ejecting even we got no lock

    if ( argc != 2 ) {
        return ERRL_INVALID_PARAM;     
    }

    char DriveLetter = argv[1][0];   // grab the drive letter only
    DriveLetter &= ~0x20;            // make uppercase

    if ( DriveLetter < 'A' || DriveLetter > 'Z' ) {
        return ERRL_INVALID_PARAM;
    }

    char szRootPath[] = "X:\\";   // "X:\"  -> for GetDriveType
    szRootPath[0] = DriveLetter;

    char szVolumeAccessPath[] = "\\\\.\\X:";   // "\\.\X:"  -> to open the volume
    szVolumeAccessPath[4] = DriveLetter;

    int res;
    DWORD dwRet;
    DWORD dwDriveType = GetDriveType(szRootPath);

    // if it is no CD drive then we try to flush the volume
    if ( dwDriveType != DRIVE_CDROM ) {
        // try to flush, write access required which only admins will get
        HANDLE hVolWrite = CreateFile(szVolumeAccessPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
        if ( hVolWrite != INVALID_HANDLE_VALUE ) {
            printf("Flushing cache...");
            res = FlushFileBuffers(hVolWrite);
            if ( res ) {
                printf(" OK\n");
            } else {
                printf(" failed  err=%u\n", GetLastError());
            }
            CloseHandle(hVolWrite);
        }
    }

    HANDLE hVolRead = CreateFile(szVolumeAccessPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
    if ( hVolRead == INVALID_HANDLE_VALUE ) {
        printf("error %u opening the volume for read access -> abort\n", GetLastError());
        return ERRL_NO_VOLREAD;
    }


    // allowing (unlocking) eject, usually for CD/DVD only, but does not hurt (and returns TRUE) for other drives
    printf("Allowing eject...");
    PREVENT_MEDIA_REMOVAL pmr = {0}; // pmr.PreventMediaRemoval = FALSE;
    res = DeviceIoControl(hVolRead, IOCTL_STORAGE_MEDIA_REMOVAL, &pmr, sizeof(pmr), NULL, 0, &dwRet, NULL);
    if ( res  ) {
        printf(" OK\n");
    } else {
        printf(" failed  err=%u\n", GetLastError());
    }


    // try to lock the volume, seems to flush too, maybe even with read access...
    printf("Locking volume...");
    int Locked = DeviceIoControl(hVolRead, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwRet, NULL);
    if ( Locked  ) {
        printf(" OK\n");
    } else {
        printf(" failed  err=%u\n", GetLastError());
    }

    if ( !Locked && !ForceEject ) {
        return ERRL_NO_LOCK;
    }

    // dismount the file system if either we got a lock or we want to force it
    printf("Dismounting volume...");
    res = DeviceIoControl(hVolRead, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwRet, NULL);
    if ( res ) {
        printf(" OK\n");
    } else {
        printf(" failed  err=%u\n", GetLastError());
    }

    printf("Ejecting media...");
    res = DeviceIoControl(hVolRead, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwRet, NULL);
    if ( res ) {
        printf(" OK\n");
    } else {
        printf(" failed  err=%u\n", GetLastError());
    }

    if ( Locked ) {
        DeviceIoControl(hVolRead, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &dwRet, NULL);
    }

    CloseHandle(hVolRead);

    if ( res ) {
        return ERRL_SUCCESS;
    }
   
    return ERRL_NO_EJECT;

}
//----------------------------------/main----------------------------------------
//-------------------------------------------------------------------------------
 
greeting,
Jimmy
User avatar
Jimmy
 
Posts: 1585
Joined: Thu Sep 05, 2019 5:32 am
Location: Hamburg, Germany

Re: DLLCALL under Fivewin

Postby Jimmy » Mon Dec 05, 2022 3:13 am

hi Enrico.
Enrico Maria Giordano wrote:You should work with warnings activated. The correct way is:

is it to use hbmk.hbm with
Code: Select all  Expand view
-w1 -es2 

for "smallest" Warning
greeting,
Jimmy
User avatar
Jimmy
 
Posts: 1585
Joined: Thu Sep 05, 2019 5:32 am
Location: Hamburg, Germany


Re: DLLCALL under Fivewin

Postby Antonio Linares » Mon Dec 05, 2022 9:14 am

Dear Jimmy,

When Harbour crashes it generates a hb_out.log file. Your example reports this:

Called from FWCALLDLL(0)
Called from DEVICEIOCONTROL(459) in jimmy.prg
Called from LOCKVOLUME(340) in jimmy.prg
Called from EJECTMEDIA(191) in jimmy.prg
Called from (b)USBEJECT(77) in jimmy.prg
Called from TBUTTON:CLICK(181) in .\source\classes\BUTTON.PRG

So the error is coming from DEVICEIOCONTROL(459)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: DLLCALL under Fivewin

Postby Jimmy » Thu Dec 08, 2022 6:05 pm

hi Antonio,

as i still can´t get a working Solution for DEVICEIOCONTROL under Fivewin i have search for HB_FUNC() to use it

this CODE does now work so far ...
Code: Select all  Expand view
#include "FIVEWIN.ch"
#include "common.ch"

PROCEDURE MAIN()
LOCAL oDlg, oListbox
LOCAL cDrive  := SPACE( 2 )
LOCAL cTitle  := "Please, select"
LOCAL aDrives := aDrives()

LOCAL bSetGet      := { | x | cDrive := x }
LOCAL bChange
LOCAL bValid
LOCAL bLDblClicked
LOCAL bWhen
LOCAL bDrawItem

   DEFINE DIALOG oDlg FROM 5, 10 TO 24, 55 TITLE cTitle

      oListbox := TListBox() :New( 10, 20, bSetGet, aDrives, 145, 95, bChange, ;
                             oDlg, bValid,,, .T., .F., ;
                             bLDblClicked,, "", .T., bWhen,, ;
                             bDrawItem, .F., .F. )

      @  7,  7 BUTTON "&OK" OF oDlg SIZE 40, 12 ;
              ACTION( USBeject( cDrive ), oDlg:End() ) DEFAULT

      @  7, 17 BUTTON "&Cancel" OF oDlg SIZE 40, 12 ;
              ACTION( cDrive := nil, oDlg:End() )

#IFDEF __HMG__
   END DIALOG
#ENDIF

   ACTIVATE DIALOG oDlg CENTERED

RETURN

STATIC PROCEDURE USBeject(cDriveLetter )
   IF EjectRemovable( cDriveLetter )
      MsgInfo( "The Drive " + cDriveLetter + " Can be Safely Removed", "Atenttion ! , Remove USB Ok" )
   ELSE
      MsgInfo( "Failed to Safely Remove/Eject Drive " + cDriveLetter , "Atenttion ! , Failed Remove USB" )
   ENDIF
RETURN


********************************************************************************
*  http://www.hmgforum.com/viewtopic.php?f=5&t=4524&hilit=cDriveLetter&start=10
*  Made By PeteWG ( Pete ) &  gfilatov (Grigory)
********************************************************************************

#pragma begindump

#include <windows.h>
#include <winioctl.h>
#include <tchar.h>
#include <stdio.h>

// Prototypes
BOOL EjectVolume(TCHAR cDriveLetter);
HANDLE OpenVolume(TCHAR cDriveLetter);
BOOL LockVolume(HANDLE hVolume);
BOOL DismountVolume(HANDLE hVolume);
BOOL PreventRemovalOfVolume(HANDLE hVolume, BOOL fPrevent);
BOOL AutoEjectVolume(HANDLE hVolume);
BOOL CloseVolume(HANDLE hVolume);

LPTSTR szVolumeFormat = TEXT("\\\\.\\%c:");
LPTSTR szRootFormat = TEXT("%c:\\");

HANDLE OpenVolume(TCHAR cDriveLetter)
{
   HANDLE hVolume;
   UINT uDriveType;
   TCHAR szVolumeName[8];
   TCHAR szRootName[5];
   DWORD dwAccessFlags;

   wsprintf(szRootName, szRootFormat, cDriveLetter);
   uDriveType = GetDriveType(szRootName);

   switch(uDriveType)
   {
   case DRIVE_REMOVABLE:
     dwAccessFlags = GENERIC_READ | GENERIC_WRITE;
     break;
   case DRIVE_CDROM:
     dwAccessFlags = GENERIC_READ;
     break;
   default:
     return INVALID_HANDLE_VALUE;
   }

   wsprintf(szVolumeName, szVolumeFormat, cDriveLetter);

   hVolume = CreateFile( szVolumeName,
                         dwAccessFlags,
                         FILE_SHARE_READ | FILE_SHARE_WRITE,
                         NULL,
                         OPEN_EXISTING,
                         0,
                         NULL );
   return hVolume;
}

BOOL CloseVolume(HANDLE hVolume)
{
   return CloseHandle(hVolume);
}

#define LOCK_TIMEOUT        10000       // 10 Seconds
#define LOCK_RETRIES        20

BOOL LockVolume( HANDLE hVolume )
{
   DWORD dwBytesReturned;
   DWORD dwSleepAmount;
   int nTryCount;

   dwSleepAmount = LOCK_TIMEOUT / LOCK_RETRIES;

   for( nTryCount = 0; nTryCount < LOCK_RETRIES; nTryCount++ )
   {
     if( DeviceIoControl( hVolume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0,
                          &dwBytesReturned, NULL ) )
         return TRUE;

     Sleep( dwSleepAmount );
   }

   return FALSE;
}

BOOL DismountVolume( HANDLE hVolume )
{
   DWORD dwBytesReturned;
   return DeviceIoControl( hVolume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0,
                           &dwBytesReturned, NULL );
}

BOOL PreventRemovalOfVolume(HANDLE hVolume, BOOL fPreventRemoval)
{
   DWORD dwBytesReturned;
   PREVENT_MEDIA_REMOVAL PMRBuffer;
   PMRBuffer.PreventMediaRemoval = fPreventRemoval;
   return DeviceIoControl( hVolume, IOCTL_STORAGE_MEDIA_REMOVAL,
                           &PMRBuffer, sizeof(PREVENT_MEDIA_REMOVAL),
                           NULL, 0, &dwBytesReturned, NULL );
}

AutoEjectVolume( HANDLE hVolume )
{
   DWORD dwBytesReturned;
   return DeviceIoControl( hVolume, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0,
                         &dwBytesReturned,
                         NULL );
}

BOOL EjectVolume( TCHAR cDriveLetter )
{
   HANDLE hVolume;

   BOOL fRemoveSafely = FALSE;
   BOOL fAutoEject = FALSE;

   hVolume = OpenVolume(cDriveLetter);
   if( hVolume == INVALID_HANDLE_VALUE )
     return FALSE;

   if( LockVolume(hVolume) && DismountVolume(hVolume) )
   {
     fRemoveSafely = TRUE;

     if (PreventRemovalOfVolume(hVolume, FALSE) && AutoEjectVolume(hVolume))
         fAutoEject = TRUE;
   }

   if( ! CloseVolume(hVolume) )
     return FALSE;

   return TRUE;
}

#include "hbapi.h"
#include "hbapifs.h"
HB_FUNC( EJECTREMOVABLE )
{
   char * szDrive = hb_parc( 1 );
   hb_retl( EjectVolume( *szDrive ) );
   return;
}

#pragma enddump

*+ EOF: FWEJECT.PRG

but those Function begin with BOOL so i can just call them from HB_FUNC() not from *.PRG

what i want :
call each BOOL Function from PRG so i can display a Message after each Step instead of only OK or FAIL

---
how to fix there Warnings
Warning W8004 FWEJECT.prg 192: 'fAutoEject' is assigned a value that is never used in function EjectVolume
Warning W8004 FWEJECT.prg 192: 'fRemoveSafely' is assigned a value that is never used in function EjectVolume
Warning W8075 FWEJECT.prg 198: Suspicious pointer conversion in function HB_FUN_EJECTREMOVABLE
greeting,
Jimmy
User avatar
Jimmy
 
Posts: 1585
Joined: Thu Sep 05, 2019 5:32 am
Location: Hamburg, Germany

Re: DLLCALL under Fivewin

Postby Enrico Maria Giordano » Thu Dec 08, 2022 7:01 pm

Jimmy wrote:how to fix there Warnings
Warning W8004 FWEJECT.prg 192: 'fAutoEject' is assigned a value that is never used in function EjectVolume
Warning W8004 FWEJECT.prg 192: 'fRemoveSafely' is assigned a value that is never used in function EjectVolume
Warning W8075 FWEJECT.prg 198: Suspicious pointer conversion in function HB_FUN_EJECTREMOVABLE


Try:

Code: Select all  Expand view
BOOL fRemoveSafely; // = FALSE;
BOOL fAutoEject; // = FALSE;


Code: Select all  Expand view
hb_retl( EjectVolume( ( TCHAR ) *szDrive ) );
User avatar
Enrico Maria Giordano
 
Posts: 8315
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: DLLCALL under Fivewin

Postby Antonio Linares » Thu Dec 08, 2022 8:40 pm

You have to write the Harbour wrappers for those C functions. In example for function BOOL DismountVolume( HANDLE hVolume ):
Code: Select all  Expand view
HB_FUNC( DISMOUNTVOLUME )
{
   hb_retl( DismountVolume( hb_parnll( 1 ) ) );
}
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: DLLCALL under Fivewin

Postby Antonio Linares » Thu Dec 08, 2022 8:46 pm

I just asked chatGPT to write them :-)

This is the result. Warning: chatGPT fails so you have to check its implementation:
Code: Select all  Expand view
HB_FUNC(EJECTVOLUME)
{
   return EjectVolume(hb_parc(1));
}

HB_FUNC(OPENVOLUME)
{
   return OpenVolume(hb_parc(1));
}

HB_FUNC(LOCKVOLUME)
{
   return LockVolume(hb_parnl(1));
}

HB_FUNC(DISMOUNTVOLUME)
{
   return DismountVolume(hb_parnl(1));
}

HB_FUNC(PREVENTREMOVALOFVOLUME)
{
   return PreventRemovalOfVolume(hb_parnl(1), hb_parl(2));
}

HB_FUNC(AUTOEJECTVOLUME)
{
   return AutoEjectVolume(hb_parnl(1));
}

HB_FUNC(CLOSEVOLUME)
{
   return CloseVolume(hb_parnl(1));
}
 
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: DLLCALL under Fivewin

Postby Antonio Linares » Thu Dec 08, 2022 8:49 pm

return should not be called in the code, instead Harbour hb_ret...() should be used

I am asking chatGPT to fix it :-D
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: DLLCALL under Fivewin

Postby Jimmy » Thu Dec 08, 2022 9:56 pm

hi Enrico,
Enrico Maria Giordano wrote:Try:

Code: Select all  Expand view
BOOL fRemoveSafely; // = FALSE;
BOOL fAutoEject; // = FALSE;


Code: Select all  Expand view
hb_retl( EjectVolume( ( TCHAR ) *szDrive ) );

thx, i will try it
greeting,
Jimmy
User avatar
Jimmy
 
Posts: 1585
Joined: Thu Sep 05, 2019 5:32 am
Location: Hamburg, Germany

PreviousNext

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 77 guests