我试图在Delphi函数中使用并释放2个指针。我如何正确地释放它们?

时间:2015-03-18 19:15:11

标签: delphi pointers delphi-xe3

我正在使用Delphi XE3。我想了解更多关于如何正确使用然后释放指针的信息。我有两个指针lpParams和pHolder。我想知道我是否必须使用pHolder的类型指针以及在此例程中释放两个pinter的正确方法。谢谢。

function TmyLine.LineOpen(dwLineDevice:        Integer;
                             var wMediaMode:  Integer;
                             phLine,
                             plTAPIVersion:       pLongInt): Integer;
  var lOwnership,
      lResult:            LongInt;
      lpParams:     pTLineCallparams;  // first pointer
      pHolder:      Pointer;                        // second pointer
      dwAddressID, dwMediaMode: DWORD;  
begin
  if not bDeviceInitialized then
    lResult := -1
  else
    begin
      pHolder := nil; // default is nil unless we are using the singleaddress method
      lOwnership := 0;
      if FPrivilege.bSingleAddress then
      begin
        lOwnership := lOwnership + LINEOPENOPTION_SINGLEADDRESS;  
        try
          lpParams := AllocMem(SizeOf(TLineCallParams) + 128);   // make up a big enough value
        except
          lpParams := nil;
          exit; // should I exit here? what about if there is an error? do I free pHolder?
        end;
        lpParams.dwTotalSize := sizeof(TLineCallParams) + 128;

        lpParams.dwAddressMode := LINEADDRESSMODE_ADDRESSID;
        pHolder := lpParams;     // is this ok? Do i need a typed pointer?
      end;

      lResult := lineOpen(Fline.hLineApp,       // fnd 64bit, see if longint needs to be dword_ptr
                          dwLineDevice,
                          phLine,
                          plTAPIVersion^,
                          FTAPI.lExtVersion,
                          DWORD_PTR(Self),  //Pointer to the control, it is passed to the Callback routine as the lCallBackInstance parameter
                          lOwnership,
                          wMediaMode,
                          pHolder);    // using the pointer here
      if lResult <> 0  then
        begin
          pHolder := nil;
          lpParams := nil; // is the the right way to do this?

          end
      else
        begin       
          lineSetStatusMessages(temp);
        end;
    end;

  pHolder := nil; //  is this the correct way to free things up?
  if lpParams <> nil then freemem(lpParams, sizeof(TLineCallParams) + 128); 
  LineOpen := lResult;
end;

1 个答案:

答案 0 :(得分:2)

首先,您正在填写dwAddressMode字段,但您没有填写dwAddressID字段。您需要填写dwAddressID,否则使用LINEOPENOPTION_SINGLEADDRESS无效。

其次,lineOpen()不会获取您传递给它的LINECALLPARAMS指针的所有权。您必须在lineOpen()退出后自行解除内存,无论其结果如何,例如:

function TmyLine.LineOpen(dwLineDevice: Integer;
                         var wMediaMode: Integer;
                         phLine,
                         plTAPIVersion: pLongInt): Integer;
var
  lOwnership: DWORD;
  lpParams: pTLineCallparams;
begin
  Result := -1;
  if not bDeviceInitialized then Exit;

  lOwnership := 0;

  lpParams := nil;
  try
    if FPrivilege.bSingleAddress then
    begin
      try
        lpParams := AllocMem(SizeOf(TLineCallParams));
      except
        Exit;
      end;

      lpParams.dwTotalSize := sizeof(TLineCallParams);
      lpParams.dwAddressID := ...; // don't forget to fill this in!
      lpParams.dwAddressMode := LINEADDRESSMODE_ADDRESSID;

      lOwnership := LINEOPENOPTION_SINGLEADDRESS;  
    end;

    Result := lineOpen(Fline.hLineApp,
                      dwLineDevice,
                      phLine,
                      plTAPIVersion^,
                      FTAPI.lExtVersion,
                      DWORD_PTR(Self),
                      lOwnership,
                      wMediaMode,
                      lpParams);
  finally
    if lpParams <> nil then
      FreeMem(lpParams, sizeof(TLineCallParams)); 
  end;

  if Result = 0 then
    lineSetStatusMessages(...);
end;

第三,由于您只填写LINECALLPARAMS的标准字段而不是任何扩展名,因此您根本不需要在堆上动态分配LINECALLPARAMS。您可以选择静态地在堆栈上分配它(这就是为什么lineOpen()无法获得它的所有权),例如:

function TmyLine.LineOpen(dwLineDevice: Integer;
                         var wMediaMode: Integer;
                         phLine,
                         plTAPIVersion: pLongInt): Integer;
var
  lOwnership: DWORD;
  Params: TLineCallparams;
  lpParams: pTLineCallparams;
begin
  Result := -1;
  if not bDeviceInitialized then Exit;

  lOwnership := 0;
  lpParams := nil;

  if FPrivilege.bSingleAddress then
  begin
    Params.dwTotalSize := sizeof(TLineCallParams);
    Params.dwAddressID := ...; // don't forget to fill this in!
    Params.dwAddressMode := LINEADDRESSMODE_ADDRESSID;

    lpParams := @Params;
    lOwnership := LINEOPENOPTION_SINGLEADDRESS;  
  end;

  Result := lineOpen(Fline.hLineApp,
                    dwLineDevice,
                    phLine,
                    plTAPIVersion^,
                    FTAPI.lExtVersion,
                    DWORD_PTR(Self),
                    lOwnership,
                    wMediaMode,
                    lpParams);
  if Result = 0 then
    lineSetStatusMessages(...);
end;