Improve company productivity with a Business Account.Sign Up

x
?
Solved

Return values from WinAPI call

Posted on 1998-06-30
11
Medium Priority
?
254 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
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
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

 
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 960 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

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

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…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
When you have multiple client accounts to manage, it often feels like there aren’t enough hours in the day. With too many applications to juggle, you can’t focus on your clients, much less your growing to-do list. But that doesn’t have to be the cas…
Through the video, you can check the migration process of Outlook PST file to PDF. Kernel for Outlook to PDF tool can convert Outlook emails with all attributes like Subject, To, From, Cc, Bcc and other folders such as Inbox, Outbox, Sent Items, Jun…

608 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