Solved

Return values from WinAPI call

Posted on 1998-06-30
11
236 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 5
11 Comments
 
LVL 8

Expert Comment

by:ZifNab
ID: 1356658
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
ID: 1356659
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
ID: 1356660
function GetInfo(VAR SerialNumber: DWORD): Boolean;
var
  dwTemp1, dwTemp2 : LongInt;
begin
  Result := GetVolumeInformation (
            'A:\', Nil, 0,
            @SerialNumber,
            dwTemp1, dwTemp2, Nil, 0);
end;

0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 1

Author Comment

by:Diver
ID: 1356661
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
ID: 1356662
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
 
LVL 3

Expert Comment

by:vladika
ID: 1356663
If something is incomprehensible, ask questions

0
 
LVL 1

Author Comment

by:Diver
ID: 1356664
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
ID: 1356665
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
ID: 1356666
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
ID: 1356667
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
ID: 1356668
Thanks, Dmitri. You've done an excellent job!
0

Featured Post

[Webinar] Learn How Hackers Steal Your Credentials

Do You Know How Hackers Steal Your Credentials? Join us and Skyport Systems to learn how hackers steal your credentials and why Active Directory must be secure to stop them. Thursday, July 13, 2017 10:00 A.M. PDT

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Michael from AdRem Software explains how to view the most utilized and worst performing nodes in your network, by accessing the Top Charts view in NetCrunch network monitor (https://www.adremsoft.com/). Top Charts is a view in which you can set seve…
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…

717 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