Results 1 to 7 of 7

Thread: Hoe geheugen te reserveren voor records?

  1. #1

    Hoe geheugen te reserveren voor records?

    Hallo,

    Ik wil in Delphi 8 gebruik maken van de functie QueryServiceConfig. Ik moet hier een variabele TQueryServiceConfig aanmeegeven waarvoor ik eerst geheugen moet reserveren. Ik kan wel voorbeelden vinden hoe ik geheugen moet reserveren voor een IntPtr en hoe deze te converteren naar een structure, maar deze worden meestal gebruikt voor aanroepen waarbij een IntPtr moet worden meegegeven. Als ik het gebruik voor de aanroep van de functie dan treedt er een exceptie op (System.ExecutionEngineException).

    Code:
    function TServiceController.GetConfig(): TQueryServiceConfig;
    var
      cbBufSize,
      pcbBytesNeeded  : DWORD;
      lpServiceConfig : TQueryServiceConfig;
      Buffer          : IntPtr;
    begin
      cbBufSize := 0;
      //Voer de functie een eerste keer uit voor het bepalen van het benodigde geheugen
      if not(QueryServiceConfig(m_hService, Result, cbBufSize, pcbBytesNeeded)) then
      begin
        Buffer := Marshal.AllocHGlobal(pcbBytesNeeded);
        try
          lpServiceConfig := TQueryServiceConfig(Marshal.PtrToStructure(Buffer, TypeOf(TQueryServiceConfig)));
          cbBufSize := pcbBytesNeeded;
          if not(QueryServiceConfig(m_hService, lpServiceConfig, cbBufSize, pcbBytesNeeded)) then
            Self.RaiseError('Could not retrieve service config, reason: "%s"', [ SysErrorMessage(GetLastError())] )
          Result := lpServiceConfig;
        finally
          Marshal.FreeHGlobal(Buffer);
        end;
      end;
    end;
    Heeft iemand een idee?

    Niels

  2. #2
    SillyMember
    Join Date
    May 2003
    Location
    Gent
    Posts
    7,725
    Waarom gebruik je de System.ServiceProcess.ServiceController klasse niet?
    All methodologies are based on fear. -- Kent Beck.

  3. #3
    SillyMember
    Join Date
    May 2003
    Location
    Gent
    Posts
    7,725
    Voorbeeldje:
    Code:
    procedure MainForm.ButtonListServices_Click(sender: System.Object; e: System.EventArgs);
    var
      SC: ServiceController;
    begin
      // Enumereer de services
      with &array(ServiceController.GetServices).GetEnumerator do
        while MoveNext do
        begin
          SC := ServiceController(Current);
          ListBox1.Items.Add(SC.DisplayName);
          // Enumereer de dependent services
          with &array(SC.DependentServices).GetEnumerator do
            while MoveNext do
              ListBox1.Items.Add('    ->' + ServiceController(Current).DisplayName);
          ListBox1.Items.Add(System.String.Create('-',150));
        end;
    end;
    All methodologies are based on fear. -- Kent Beck.

  4. #4
    Omdat ik niet alle code wil omschrijven en het ook meer een algemene vraag is. Hoe kan ik geheugen reserveren voor een record (met variabele grootte) en deze doorgeven aan een functie die een record wil i.p.v. een untype buffer.

    De functie definitie van QueryServiceConfig is trouwens alsvolgt:

    function QueryServiceConfig(hService: SC_HANDLE; out lpServiceConfig: TQueryServiceConfig; cbBufSize: DWORD; out pcbBytesNeeded: DWORD): BOOL;

  5. #5
    SillyMember
    Join Date
    May 2003
    Location
    Gent
    Posts
    7,725
    1) Je gaat toch de code moeten herschrijven, en dat lijkt me een stuk makkelijker en aangenamer als je de in het .NET framework aanwezige klassen gebruikt (die doen namelijk al wat jij probeert
    2) Zou zoiets moeten zijn (ServiceInfo record is hier de managed versie van het record of de klasse die overeenstemt met jouw TQueryServiceConfig).
    Code:
    implementation
    uses System.Runtime.InteropServices;
    
    {$AUTOBOX ON}
    
    const
      GENERIC_ALL: integer = $10000000;
      QUERY_CONFIG: integer = $1;
      CHANGE_CONFIG:integer = $2;
    
    type
      // wat we meegeven
      [StructLayout(LayoutKind.Sequential)]
      QueryServiceConfigStruct = packed record
      public
        serviceType: Integer;
        startType: Integer;
        errorControl: Integer;
        binaryPathName: IntPtr;
        loadOrderGroup: IntPtr;
        tagID: Integer;
        dependencies: IntPtr;
        startName: IntPtr;
        displayName: IntPtr;
      end;
    
      //wat we opvullen
        ServiceInfo = record
        public
          serviceType: Integer;
          startType: Integer;
          errorControl: Integer;
          binaryPathName: string;
          loadOrderGroup: string;
          tagID: Integer;
          dependencies: string;
          startName: string;
          displayName: string;
        end;
    
    
    
    [DllImport('advapi32.dll', SetLastError=True, CharSet=CharSet.Auto)]
    class function QueryServiceConfig(
      service: IntPtr; queryServiceConfig: IntPtr;
      bufferSize: Integer; var bytesNeeded: Integer): Integer;external;
    
    [DllImport('advapi32.dll', SetLastError=True, CharSet=CharSet.Auto)]
    class function OpenSCManager(machineName: string; databaseName: string;
       desiredAccess: Integer): IntPtr;external;
    
    [DllImport('advapi32.dll', SetLastError=True, CharSet=CharSet.Auto)]
      class function OpenService(scManager: IntPtr; serviceName: string;
      desiredAccess: Integer): IntPtr;external;
    
    
    
    class function GetServiceInfo(ServiceName: string): ServiceInfo;
    var
      retCode: Integer;
      qscPtr: IntPtr;
      qscs: QueryServiceConfigStruct;
      bytesNeeded: Integer;
      service: IntPtr;
      scManager: IntPtr;
    begin
      scManager := OpenSCManager('.', nil, GENERIC_ALL);
      if (scManager.ToInt32 <= 0) then
        raise Win32Exception.Create;
      service := OpenService(scManager, ServiceName, QUERY_CONFIG);
      if (service.ToInt32 <= 0) then
        raise NullReferenceException.Create;
      bytesNeeded := 5;
    
      qscPtr := Marshal.AllocCoTaskMem(0);
      retCode := QueryServiceConfig(service, qscPtr, 0, bytesNeeded);
      if ((retCode = 0) and (bytesNeeded = 0)) then
        raise Win32Exception.Create
      else
      begin
        qscPtr := Marshal.AllocCoTaskMem(bytesNeeded);
        retCode := QueryServiceConfig(service, qscPtr, bytesNeeded, bytesNeeded);
        if (retCode = 0) then
          raise Win32Exception.Create;
        qscs.binaryPathName := IntPtr.Zero;
        qscs.dependencies := IntPtr.Zero;
        qscs.displayName := IntPtr.Zero;
        qscs.loadOrderGroup := IntPtr.Zero;
        qscs.startName := IntPtr.Zero;
        qscs := QueryServiceConfigStruct(
          Marshal.PtrToStructure(
            qscPtr, TypeOf(QueryServiceConfigStruct)));
      end;
      Result.binaryPathName := Marshal.PtrToStringAuto(qscs.binaryPathName);
      Result.dependencies := Marshal.PtrToStringAuto(qscs.dependencies);
      Result.displayName := Marshal.PtrToStringAuto(qscs.displayName);
      Result.loadOrderGroup := Marshal.PtrToStringAuto(qscs.loadOrderGroup);
      Result.startName := Marshal.PtrToStringAuto(qscs.startName);
      Result.errorControl := qscs.errorControl;
      Result.serviceType := qscs.serviceType;
      Result.startType := qscs.startType;
      Result.tagID := qscs.tagID;
    
      Marshal.FreeCoTaskMem(qscPtr);
    
    end;
    All methodologies are based on fear. -- Kent Beck.

  6. #6
    SillyMember
    Join Date
    May 2003
    Location
    Gent
    Posts
    7,725
    Ook: misschien best een try.. finally (of een test) gebruiken om het geheugen gegarandeerd vrij te geven, want ik zie nu dat dit niet gerandeerd is in bovenstaande code.
    All methodologies are based on fear. -- Kent Beck.

  7. #7
    Okee, dank je wel, dit lijkt te werken. Misschien is er nog een andere
    manier, maar misschien heeft Borland wel een fout gemaakt met z'n
    declaraties in Borland.Vcl.WinSvc. Ik heb het nog wel iets gesimplificeerd,
    nl. geen gebruik gemaakt van een tussen record met IntPtr's i.p.v. strings.


    Code:
    [DllImport('advapi32.dll', SetLastError=True, CharSet=CharSet.Auto)]
    function QueryServiceConfig(hService: SC_HANDLE;
      lpServiceConfig: IntPtr; cbBufSize: DWORD;
      out pcbBytesNeeded: DWORD): BOOL; external;
    
    function TServiceController.GetConfig(): TQueryServiceConfig;
    var
      cbBufSize,
      pcbBytesNeeded  : DWORD;
      Buffer          : IntPtr;
      bRet            : boolean;
    begin
      cbBufSize := 0;
      Buffer := Marshal.AllocCoTaskMem(cbBufSize);
      try
        bRet := WinSvcCtrl.QueryServiceConfig(m_hService, Buffer, 
          cbBufSize, pcbBytesNeeded)
      finally
        Marshal.FreeCoTaskMem(Buffer);
      end;
      if not(bRet) then
      begin
        Buffer := Marshal.AllocCoTaskMem(pcbBytesNeeded);
        try
          cbBufSize := pcbBytesNeeded;
          bRet := QueryServiceConfig(m_hService, Buffer, cbBufSize, 
            pcbBytesNeeded);
        finally
          Marshal.FreeCoTaskMem(Buffer);
        end;
      end;
      if (bRet) then
        Result := TQueryServiceConfig(Marshal.PtrToStructure(Buffer, 
          TypeOf(TQueryServiceConfig)))
      else
        Self.RaiseError('Could not retrieve service config, reason: "%s"',
          [ SysErrorMessage(GetLastError())] );
    end;

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Similar Threads

  1. hoe doet men dit?
    By pdebie in forum Koffiehoek
    Replies: 17
    Last Post: 08-Oct-02, 17:59
  2. nieuw in het forum hoe...???
    By real-one in forum Koffiehoek
    Replies: 13
    Last Post: 08-Sep-02, 21:33
  3. Opvragen beschikbaar geheugen Server
    By Maiko in forum Algemeen
    Replies: 1
    Last Post: 14-May-02, 11:11
  4. Pointer, Buffer, Pchar en conversie hiervan.
    By Richard in forum Algemeen
    Replies: 3
    Last Post: 11-Aug-01, 01:35

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •