Solved

Return values from WinAPI call

Posted on 1998-06-30
11
221 Views
Last Modified: 2010-04-04
This procedure returns false if no diskette is found in drive A, otherwise it returns true. When it returns true I want to retrieve the serial number in the 'result' variable. How could this be done?


procedure GetInfo ;export;
  var
     dwTemp1, dwTemp2 : LongInt;
     Result : DWord;
  begin
     GetVolumeInformation (
        PChar('A:\'),
        Nil,
        0,
        @Result,
        dwTemp1,
        dwTemp2,
        Nil,
        0);
  end;

  exports
     GetInfo;

0
Comment
Question by:Diver
  • 5
  • 5
11 Comments
 
LVL 8

Expert Comment

by:ZifNab
Comment Utility
Hi Diver,

Getting the serial number of a disk.

                         Question:

                         How do I retrieve the serial number of a disk?

                         Answer:

                         You can use the Windows API function GetVolumeInformation()

                         procedure TForm1.Button1Click(Sender: TObject);
                         var
                           VolumeSerialNumber : DWORD;
                           MaximumComponentLength : DWORD;
                           FileSystemFlags : DWORD;
                           SerialNumber : string;
                         begin
                           GetVolumeInformation('C:\',
                                                nil,
                                                0,
                                                @VolumeSerialNumber,
                                                MaximumComponentLength,
                                                FileSystemFlags,
                                                nil,
                                                0);
                           SerialNumber := IntToHex(HiWord(VolumeSerialNumber), 4) +
                                           '-' +
                                           IntToHex(LoWord(VolumeSerialNumber), 4);
                           Memo1.Lines.Add(SerialNumber);
                         end;
(From Borlands developer support)

Regards, ZiF.
0
 
LVL 1

Author Comment

by:Diver
Comment Utility
Yes, I know how to retrieve it. But how can it be returned from a function in a dll? I want to return both the value of the GetVolumeInformation function as the serial number in the 4th parameter. That's what I was asking for.
0
 
LVL 3

Expert Comment

by:vladika
Comment Utility
function GetInfo(VAR SerialNumber: DWORD): Boolean;
var
  dwTemp1, dwTemp2 : LongInt;
begin
  Result := GetVolumeInformation (
            'A:\', Nil, 0,
            @SerialNumber,
            dwTemp1, dwTemp2, Nil, 0);
end;

0
 
LVL 1

Author Comment

by:Diver
Comment Utility
Vladika, I don't think you tested your code. When inserting a disk I get an acces violation error at address...

OK, it looks like it is not that easy... hmm, let me raise the points... hope I get the right answer this time.

I want to use Win API calls like GetVolumeInfo and GetComputerName in functions in a DLL.
So, the result of this function has to be exported.
But, I also want to export the value of certain parameters, like the name of the GetComputerName call and the serial number of the GetVolumeInfo call.

Please provide me with the correct code for BOTH calls. A brief explanation of what exactly is happening would be welcome too. This is new stuff to me and I want to learn something from you.

I hope I made myself clear.
0
 
LVL 3

Accepted Solution

by:
vladika earned 240 total points
Comment Utility
Ok. You are right. I forget about stdcall
Try this

library mylib;

uses
  Windows,
  SysUtils,
  Classes;

type
  TCompName = array [0..MAX_COMPUTERNAME_LENGTH] of Char;

function GetInfo(var SerialNumber: DWORD): Boolean; stdcall; // use stdcall calling convention
 // use var to export SerialNumber
var
  dwTemp1, dwTemp2 : LongInt;
begin
  Result := GetVolumeInformation('A:\', nil, 0, @SerialNumber,
    dwTemp1, dwTemp2, nil, 0);
end;

function GetCompName(var CompName: TCompName): Boolean; stdcall; // use stdcall
var L: Integer;
begin
  L := SizeOf(CompName);
  Result := GetComputerName(CompName, L); // CompName have MAX_COMPUTERNAME_LENGTH + 1 characters
end;

exports
  GetInfo index 1,
  GetCompName index 2;
 
begin
end.


How to use
type
  TCompName = array [0..MAX_COMPUTERNAME_LENGTH] of Char; // redeclare TCompName since we cannot export type definition

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function GetInfo(var SerialNumber: DWORD): Boolean; stdcall; external 'mylib.dll'; // import GetInfo
function GetCompName(var CompName: TCompName): Boolean; stdcall; external 'mylib.dll'; // import GetCompName

procedure TForm1.Button1Click(Sender: TObject);
var SN: Integer;
    S: string;
begin
  SN := 0;
  if GetInfo(SN) then
  begin
    S := 'Serial Number: ' +
      IntToHex(HiWord(SN), 4) + '-' + IntToHex(LoWord(SN), 4);
    Application.MessageBox(PChar(S), '', 0)
  end else
    Application.MessageBox('Insert disk', 'Error', 0);
end;

procedure TForm1.Button2Click(Sender: TObject);
var CompName: TCompName;
begin
  if GetCompName(CompName) then
    Application.MessageBox(CompName, 'ComputerName', 0)
  else
    Application.MessageBox('Cannot find computer name', 'Error', 0)
end;

0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 3

Expert Comment

by:vladika
Comment Utility
If something is incomprehensible, ask questions

0
 
LVL 1

Author Comment

by:Diver
Comment Utility
Hello, Vladika. This works fine now. Excellent work! Sorry for my nervous reaction yesterday; suppose I was doing to much things at a time. Can I still ask you a few questions? I'll raise the points to 120 to compensate for your effort. BTW, are you Russian or is this just a good sounding nickname :-) ?

How come that the serial number is returned in the 'result' variable and not the boolean output of the GetVolumeInformation itself?

Why has CompName to be defined as an array of char? Can't it be returned as a string?

The GetVolumeInformation function now only reads drive A (hard coded). How would this function be written if the drive letter is an input variable coming from a textbox on a form? (the function is always called from the dll, so the drive letter has to be passed from the form to the dll).

Hope this is a bit clear. Anyway, thanks for helping me that much.
0
 
LVL 3

Expert Comment

by:vladika
Comment Utility
Hello, Diver.

Yes, I am Russian. I think you guessed by my bad English :)

> How come that the serial number is returned in the 'result' variable and not the boolean
> output of the GetVolumeInformation itself?
> How would this function be written if the drive letter is an input variable coming
> from a textbox on a form?

Here is example
................
function GetInfo2(Drive: PChar): DWORD; stdcall;
var
  dwTemp1, dwTemp2 : LongInt;
begin
  if not GetVolumeInformation(Drive, nil, 0, @Result,
    dwTemp1, dwTemp2, nil, 0) then Result := 0;  // '0' indicates error
end;
................
exports
  GetInfo2 index 3;
................

In the program
...........
function GetInfo2(Drive: PChar): DWORD; stdcall; external 'mylib.dll';
...........
procedure TForm1.Button3Click(Sender: TObject);
var SN: Integer;
    S: string;
begin
  SN := GetInfo2(PChar(Edit1.Text));
  if SN <> 0 then // no error
  begin
    S := 'Serial Number: ' +
      IntToHex(HiWord(SN), 4) + '-' + IntToHex(LoWord(SN), 4);
    Application.MessageBox(PChar(S), '', 0)
  end else
    RaiseLastWin32Error;
end;


> Why has CompName to be defined as an array of char?
array of char is equvalent PChar
You must pass in GetComputerName buffer which
should be large enough to contain MAX_COMPUTERNAME_LENGTH + 1 characters
So, TCompName is
1) PChar
2) have enough size to contain MAX_COMPUTERNAME_LENGTH + 1 characters

> Can't it be returned as a string?
I don't try such thing.
I think the problems appears with using this dll in not Delphi.
Use PChar instead of string.

0
 
LVL 1

Author Comment

by:Diver
Comment Utility
Vladika, it was not your English, but your name that made me think you're Russian. BTW, your English is not bad at all (mine is not perfect either, because it's not my native language).
Thanks for answering all my question. Thanks also for the code: this works fine too.
I just want to ask you one more favor (and I'm raising the points again - in fact I'm planning to double them :-) - if you can answer me). I have a homemade C++ dll that reads and writes to sectors on a disk, and sets a volume id. What follows are the declarations in the header file.
Can this dll be called from my dll? Can you do that in Delphi code?

Functions:
----------
ReadFloppySectors(drive, sector, num, buffer)
WriteFloppySectors(drive, sector, num, buffer)
SetVolumeId(drive, id)

Arguments:
----------
drive      - Floppy drive number (0 = "A:", 1 = "B:")
sector      - First sector number
num      - Number of sectors
buffer      - Address of allocated buffer
                    Buffer size must be a multiple of sector size (usually 512 bytes)
id      - A 32-bit hex representation

0
 
LVL 3

Expert Comment

by:vladika
Comment Utility
Hi, Diver

> Can this dll be called from my dll? Can you do that in Delphi code?
Yes, yes.

But information is not enough.
Before write dll I must know
1) parameters types
2) calling convention
3) procedure import name or index
4) your dll name

You can send me dll and header file by email
demon@dezcom.mephi.ru

Or write here missing information

0
 
LVL 1

Author Comment

by:Diver
Comment Utility
Thanks, Dmitri. You've done an excellent job!
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now