I have a challange: create a program which takes an image from a web-camera when a button is pressed. Additional condition: do not use third-party components (like DSPack), just the WinAPI. I wrote the following code.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls,ShellAPI;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Panel1: TPanel;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const WM_CAP_START = WM_USER;
WM_CAP_STOP = WM_CAP_START + 68;
WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10;
WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11;
WM_CAP_SAVEDIB = WM_CAP_START + 25;
WM_CAP_GRAB_FRAME = WM_CAP_START + 60;
WM_CAP_SEQUENCE = WM_CAP_START + 62;
WM_CAP_FILE_SET_CAPTURE_FILEA = WM_CAP_START + 20;
function capCreateCaptureWindowA(lpszWindowName : PCHAR;
dwStyle : longint;
x : integer;
y : integer;
nWidth : integer;
nHeight : integer;
ParentWin : HWND;
nId : integer): HWND;
stdcall external 'AVICAP32.DLL';
var
Form1: TForm1;
implementation
{$R *.dfm}
var hWndC : THandle;
procedure TForm1.Button1Click(Sender: TObject);
begin
hWndC := capCreateCaptureWindowA('My Own Capture Window',
WS_CHILD or WS_VISIBLE ,
0,
0,
Panel1.Width,
Panel1.Height,
Panel1.Handle,
0);
if hWndC <> 0 then
SendMessage(hWndC, WM_CAP_DRIVER_CONNECT, 0, 0);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
hWndC := 0;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if hWndC <> 0 then
begin
SendMessage(hWndC, WM_CAP_DRIVER_DISCONNECT, 0, 0);
hWndC := 0;
end;
end;
end.
There are two buttons and a panel on the form. The program compiles successfully, and works well when launched the first time; however, at second and subsequent launches there appears a window which offers to select a device, but even after selecting it is not working. I would guess that after the first launch, the program is not returning the camera's driver to its original state.
Is this so? If it is, how can I correct it? If not, why does the program not work on second and other launches? Thanks for suggestions.
First of all, I wont be able to really help you with your current code, then again i think no one will so here is an alternative.
I understand you don't want to use a 3e party component but I think using AVICAP32.DLL is not a better option.
This page offers a great way to use webcams under windows, its very reliable and allows you to set any cam property. Its all opensource, easy to use and based on native windows DirectX libraries.
It has never failed me.
http://www.delphibasics.info/home/delphibasicsprojects/directxdelphiwebcamcaptureexample
Good luck and have fun,
Delphi rocks.
Related
After installed MS Powerpoint Viewer, I run the code below
unit Unit1;
interface
uses Comobj,
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls,Office_TLB, office97, PowerPointXP;//, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Panel1: TPanel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
const
ppShowTypeSpeaker = 1;
ppShowTypeInWindow = 1000;
SHOW_FILE = 'C:\Users\myname\Downloads\practicepowerpoint.ppt';
var
oPPTApp: OleVariant;
oPPTPres: OleVariant;
screenClasshWnd: HWND;
pWidth, pHeight: Integer;
function PixelsToPoints(Val: Integer; Vert: Boolean): Integer;
begin
if Vert then
Result := Trunc(Val * 0.75)
else
Result := Trunc(Val * 0.75);
end;
begin
try
oPPTApp := CreateOleObject('PowerPoint.Application');
except
showmessage('no ppt');;
exit;
end;
oPPTPres := oPPTApp.Presentations.Open(SHOW_FILE, True, True, False);
pWidth := PixelsToPoints(Panel1.Width, False);
pHeight := PixelsToPoints(Panel1.Height, True);
oPPTPres.SlideShowSettings.ShowType := ppShowTypeSpeaker;
oPPTPres.SlideShowSettings.Run.Width := pWidth;
oPPTPres.SlideShowSettings.Run.Height := pHeight;
screenClasshWnd := FindWindow('screenClass', nil);
Windows.SetParent(screenClasshWnd, Panel1.Handle);
end;
end.
the line
oPPTApp := CreateOleObject('PowerPoint.Application');
causes error.
Just wonder if I have to install Powerpoint rather than Powerpoint Viewer before run the code
Your comment welcome
Yes, "Powerpoint.Application" starts Powerpoint. I would not recommend to use the powerpoint viewer because it is a really old program (from 2010 and before). I am not shure if you can automate this program.
The new way to view pptx is Powerpoint online
I am new to Delphi.
I would like to make an application in which will create a number of Buttons. Declaring an array of Tbuttons and create the buttons 1 by 1 is not very satisfying, because it is confusing and takes a lot of time. Using the Command For is also unsatisfying, because i won't be able to change some of button's properties, if needed, for example their position.
So i decided to declare a procedure in TForm1 Class, which creates the buttons based on what properties I send to the procedure. But for some reason it is not working (There aren't any syntax Errors):
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm) //Declaring the procedure
procedure CreateButton(Button: TButton; L: Integer; T: Integer);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
B1, B2: TForm1; //Declaring controls
implementation
{$R *.dfm}
procedure TForm1.CreateButton(Button: TButton; L: Integer; T: Integer);
begin
Button:= TButton.Create(Self);
Button.Parent:= Self;
Button.Width:= 100; Button.Height:= 50;
Button.Left:= L; Button.Top:= T;
end;
procedure TForm1.FormCreate(Sender: TObject);
Var
Button1, Button2: TButton;
begin
B1.CreateButton(Button1, 100, 50); //Sending properties
B2.CreateButton(Button2, 200, 40); //Sending properties
end;
end.
AS: during the communication with topic starters answer grown too. The total outcome is like http://pastebin.ca/2426760
procedure TForm1.CreateButton(VAR Button: TButton; CONST L: Integer; CONST T: Integer);
That is of basics of Pascal language how to pass parameters to procedures/functions.
http://docwiki.embarcadero.com/RADStudio/XE4/en/Parameters_(Delphi)
Actually, I don't think there is any problem with the parameters
Button = nil, which means the values of "Button1" and "Button2" are not sent, however
http://pastebin.ca/2427238
Kudoes to Bill for spotting this. Using separate properties to position your controls is both inefficient and prone to copy-paste errors.
http://docwiki.embarcadero.com/Libraries/XE3/en/Vcl.Controls.TControl.SetBounds
http://docwiki.embarcadero.com/CodeExamples/XE3/en/BoundsRect_(Delphi)
Using the 2nd link:
procedure TForm1.CreateButton(out Button: TButton; const L: Integer; const T: Integer);
begin
Button:= TButton.Create(Self);
Button.Parent:= Self;
Button.SetBounds( L, T, 100, 50);
end;
Actually what do you do with pointers to newly created buttons ?
In your code you just loose them!
procedure TForm1.FormCreate(Sender: TObject);
Var
Button1, Button2: TButton;
begin
...
end;
In this your code those pointers would be just lost! If you do need those values - pass them outside of the procedure. If you do not - do not ask for them - http://en.wikipedia.org/wiki/YAGNI http://en.wikipedia.org/wiki/KISS_principle
Procedure TForm1.CreateButton(const L, T: Integer);
begin
With TButton.Create(Self) do begin
Parent := Self;
SetBounds( L, T, 100, 50);
Caption := 'Caption at ' + IntToStr(T);
Name := 'Name at ' + IntToStr(L);
End;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
B1.CreateButton( 100, 50); //Sending properties
B2.CreateButton( 200, 40); //Sending properties
end;
Now to those B1, B2...
You claim that you want 2 buttons on the form, but you code shows you try to make THREE FORMS and one button on the 2nd form and one button on the 3rd form. So what do you really want ??? And do you check that B1 and B2 forms were created befoe tryign to add buttons to them ?
Perhaps you really wanted
procedure TForm1.FormCreate(Sender: TObject);
begin
SELF.CreateButton( 100, 50); //Sending properties
SELF.CreateButton( 200, 40); //Sending properties
end;
Then to go with DRY principle and to keep all the variables in one place.
http://docwiki.embarcadero.com/Libraries/XE2/en/System.Types.TPoint
Procedure TForm1.CreateButtons(const a: array of TPoint);
Var p: TPoint;
Begin
for p in a do
CreateButton( p.x, p.y );
End;
type TPointDynArray = array of TPoint;
procedure TForm1.FormCreate(Sender: TObject);
begin
CreateButtons( TPointDynArray.Create(
Point( 100,50 ), Point(200, 40) ) );
end;
Kudos to Delphi array initialization
Later you can always add more coordinates to an array and keep it consistent.
Well, to bring down this to Delphi 7 abilities that would - somewhat redundantly - be coded like
const BtnCnt = 2;
BtnLocations : array [1..BtnCnt] of TSize = (
( cx: 100, cy: 50 ), ( cx: 200, cy: 40 )
);
Procedure TForm1.CreateButtons(const a: array of TSize);
Var i: integer;
Begin
for i := Low(a) to High(a) do
with a[i] do
CreateButton( cx, cy );
End;
procedure TForm1.FormCreate(Sender: TObject);
begin
CreateButtons( BtnLocations );
end;
But while Delphi 5 and Dephi 7 were great releases, they are very outdated. I definitely suggest you either upgradeing to Delphi XE or more recent, or side-stepping to CodeTyphon
TForm1 = class(TForm) //Declaring the procedure
procedure CreateButton(Button: TButton; L: Integer; T: Integer);
Declaring that one-purpose procedure in PUBLISHED section of the form class is also not a very good style. You'd better declare them in PRIVATE section. Adhering to "least visibility" would help you to make interdependencies controllable. Otherwise in a year your program would become a spaghetti mess, where you just cannot change anything without ruining everything else. I am workign on a project with 10+ years of history now and i see the consequences of "everything is public" very clear. It is a great pain!
I have two scenarios. One works, one does not. The first (the one that works) invloves a scrollbox sitting directly on a form that when a button is pushed it executes this code:
procedure TForm1.Button2Click(Sender: TObject);
begin
DrawPanel;
end;
procedure TForm1.DrawPanel;
begin
BuildPanel; //Resides on a seperate unit code pasted below
TestPanel.Height := 40;
TestPanel.Width := 100;
TestPanel.Left := Trunc(ScrollBox1.Width / 2) - Trunc(TestPanel.Width / 2);
TestPanel.Top := Trunc(ScrollBox1.Height / 2) - Trunc(TestPanel.Height / 2);
TestPanel.Visible := True;
TestPanel.Parent := ScrollBox1;
end;
unit Unit3;
interface
uses ExtCtrls;
Var
TestPanel : Tpanel;
Procedure BuildPanel;
implementation
procedure BuildPanel;
begin
TestPanel := TPanel.Create(Nil);
end;
end.
The code is identical except for a small difference in the second scenario. The scrollbox sits on a frame that is added to the Templates palette and then dropped down on the form. The button click calls:
procedure TForm1.Button1Click(Sender: TObject);
begin
TestFrame.DrawPanel;
end;
procedure TTestFrame.DrawPanel;
begin
BuildPanel; //Still points to the unit3 code above
TestPanel.Height := 40;
TestPanel.Width := 100;
TestPanel.Left := Trunc(ScrollBox1.Width / 2) - Trunc(TestPanel.Width / 2);
TestPanel.Top := Trunc(ScrollBox1.Height / 2) - Trunc(TestPanel.Height / 2);
TestPanel.Visible := True;
TestPanel.Parent := ScrollBox1;
end;
However the panel will not display in the scrollbox that sits on the frame, when triggered at runtime. I'm not really sure why, can anybody help out? I hope I was specific enough in my question, let me know if anything is unclear. Thanks in advance.
Here's all the code in order.....Hopefully it make it more clear:
//This is the form
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Unit2, Unit3;
type
TForm1 = class(TForm)
Button1: TButton;
TTestFrame1: TTestFrame;
ScrollBox1: TScrollBox;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
TestFrame: TTestFrame;
Procedure DrawPanel;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
TestFrame.DrawPanel;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
DrawPanel;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
TestFrame.Free;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
TestFrame := TTestFrame.Create(Form1);
end;
procedure TForm1.DrawPanel;
begin
BuildPanel;
TestPanel.Height := 40;
TestPanel.Width := 100;
TestPanel.Left := Trunc(ScrollBox1.Width / 2) - Trunc(TestPanel.Width / 2);
TestPanel.Top := Trunc(ScrollBox1.Height / 2) - Trunc(TestPanel.Height / 2);
TestPanel.Visible := True;
TestPanel.Parent := ScrollBox1;
end;
end.
//This is the frame
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Unit3;
type
TTestFrame = class(TFrame)
ScrollBox1: TScrollBox;
private
{ Private declarations }
public
{ Public declarations }
Procedure DrawPanel;
end;
implementation
{$R *.dfm}
{ TTestFrame }
procedure TTestFrame.DrawPanel;
begin
BuildPanel;
TestPanel.Height := 40;
TestPanel.Width := 100;
TestPanel.Left := Trunc(ScrollBox1.Width / 2) - Trunc(TestPanel.Width / 2);
TestPanel.Top := Trunc(ScrollBox1.Height / 2) - Trunc(TestPanel.Height / 2);
TestPanel.Visible := True;
TestPanel.Parent := ScrollBox1;
end;
end.
//This is the unit that mocks my data structure
//In reality it creates an Array of Tpanel that is part of a class.
unit Unit3;
interface
uses ExtCtrls;
Var
TestPanel : Tpanel;
Procedure BuildPanel;
implementation
procedure BuildPanel;
begin
TestPanel := TPanel.Create(Nil);
end;
end.
You just forgot to assign a parent to your dynamic created TestFrame.
Delphi 6 project
I have searched google pretty thorough but am not finding the answers to my delima. basically i want to have the timecode and videos framerate of a current screen capture session showing in my app, in the statusbar or label. i also need this with respect to syncing the captures to the framerate of the sofware player playing the video, otherwise i get a lot of duplicate or missed frames. the videos are 29.970 and 23.976 fps. So i need to be able to configure for both, somehow.
Currently, I can screen capture from tv cards and software video players like, vlc, ffplay, mplayer, virtualdub, etc.
i'm not sure how to implement the necessary routines into mine, let alone where. i've been reading a lot about the following items below but they are all over my head though i did make many attempts at it:
timer1 control -- setting interval to 34 is not exact, it duplicates or misses frames during screen capture
gettimetick and timegettime
timeBeginPeriod and timeEndPeriod
QueryPerformanceTimer and QueryPerformanceCounter
To help simiplfy the process, i snipped a lot of code of the original project to only feature the screen capturing. Here is the complete routine (along with some remarked-out experimental code) for this:
(thanks in advanced for any help)
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, mmsystem,
ExtCtrls, clipbrd, DXClass;
type
TForm1 = class(TForm)
Timer1: TTimer;
Panel1: TPanel;
m1: TMemo;
btnCapOnOff: TButton;
txtHandle: TEdit;
Edit2: TEdit;
stDataRate: TStaticText;
btnCopy: TButton;
btnSetHDC: TButton;
dxt1: TDXTimer;
sb1: TScrollBox;
Splitter1: TSplitter;
im1: TImage;
procedure btnCapOnOffClick(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure capturewindow;
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure btnCopyClick(Sender: TObject);
procedure btnSetHDCClick(Sender: TObject);
procedure dxt1Timer(Sender: TObject; LagCount: Integer);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
start,
finish : cardinal; //int64;
i : integer;
s : string;
bm: tbitmap;
dc: hdc=0;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
form1.DoubleBuffered:=true;
sb1.DoubleBuffered:=true; // this is a scrollbox control
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
im1.Picture.Bitmap.PixelFormat:=pf24bit;
im1.Width:=352;
im1.Height:=240;
end;
procedure TForm1.btnSetHDCClick(Sender: TObject);
begin
if dc=0 then dc := getdc(strToint(txtHandle.text));
end;
procedure TForm1.capturewindow;
begin
//timeBeginPeriod(1);
start := timegettime;
//sleep(1);
bitblt(bm.canvas.Handle, 0,0, 352,240, dc, 0,0, srccopy);
finish := timegettime-start;
//m1.lines.Add(intTostr(finish)); // debugging: to spill out timing values, etc.
im1.Picture.Bitmap := bm;
stDataRate.Caption := 'Date Rate: '+intTostr(finish) + ' fps or ms';
end;
procedure TForm1.dxt1Timer(Sender: TObject; LagCount: Integer);
begin
capturewindow;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
// capturewindow; // timer1 is too slow or unpredictable
end;
// button: a cheeters way to turn On or Off capturing
procedure TForm1.btnCapOnOffClick(Sender: TObject);
begin
if btnCapOnOff.caption='Cap is Off' then begin
btnCapOnOff.caption:='Cap is On';
//timer1.Enabled:=true; // capture the window // too slow
dxt1.Enabled:=true; // capture the window // a better timer control component (delphiX)
end else begin
btnCapOnOff.Caption:='Cap is Off';
//timer1.Enabled:=false; // too slow
dxt1.Enabled:=false; // stop capturing the window // a better timer control component (delphiX)
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
bm.free;
releaseDC(dc,dc);
//timeEndPeriod(1);
end;
procedure TForm1.btnCopyClick(Sender: TObject);
begin
clipboard.assign(im1.picture.bitmap); // to take quick pics
end;
initialization
bm := tbitmap.Create;
bm.PixelFormat:=pf24bit;
bm.Width:=352;
bm.Height:=240; beep;
end.
Actually hooking the software that's playing the video, and synchronizing to it, I'm not sure how to do that. But working on timing might help out. Assuming that the software playing the video is also well timed, you should be able to get a smooth capture.
This tutorial is useful: http://www.codeproject.com/Articles/1236/Timers-Tutorial
The "Multimedia Timers" offer good resolution (down to 1ms on most machines), and I've found them to be reliable.
What I would try is using the Performance Timer (queryperformancetimer, as you've already mentioned) to time your "CaptureWindow" procedure. Then, when you call "timesetevent" in a multimedia timer, subtract the amount of time the capture took from the overall time of a single frame, and use that as your "uDelay" value.
HowLongTimerShouldWait := LengthOfASingleFrame - TimeSpentCapturingPreviousFrame
The nice thing about the Multimedia Timers is that they let you use it as a 'one shot', where each interval can have a different delay period. I've generally set the timer to call a single procedure recursively, until it's flagged to stop.
This way, with a bit of fine tuning, you should be able to get capture rates are are within a +/-1ms tolerance of the actual video FPS.
As promised, here is the code i came up with based on some google searches and working them out in delphi. the following links did help me out some though (but due to c/c++/c# i could not translate as easily to delphi) so most of the final answer were based on lots of trial and error:
http://www.andrewduncan.ws/Timecodes/Timecodes.html
http://puredata.hurleur.com/sujet-990-framenumber-timecode-conversion
To my knowledge the routine works flawless. but just so you know, i like my numbers formated for spacing purposes, so i padded to 2-digits, this way there is not shriking back and forth as numbers progress past 59.
Heres how it works:
It computes the timecode based on the frame rate of your video source (ie 29.970 interlace or progressive, and 23.976 for 24p film) .. so just feed it a frame number and the function will return the timecode in string format.
Example Preporation/Useage:
put two Tedit's and one Tbutton control on your form1
in button1 onClick event, enter this: edit2.text := frameNo2timecode(strToint(edit1.text), 29.970);
now, run the program and enter your frame number in the first edit1.text
then, press the button1 control, it will compute the timecode in edit2.text
source code to calculate timecode:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, math;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function FrameNo2Timecode(fn: longint; rate: real): string;
var
hours,mins,secs,milli: extended;
hoursStr, minsStr, secsStr, milliStr: string;
function padzero(N: longint; Len: Integer): string;
begin
FmtStr(Result, '%d', [N]);
while Length(Result) < Len do
Result := '0' + Result;
end;
begin
hours := floor( (fn/rate)/3600) mod 60;
hoursStr := padzero(floor(hours),2);
mins := floor( (fn/rate)/60.0) mod 60;
minsstr := padzero(floor(mins),2);
secs := floor( (fn/rate)) mod 60;
secsstr := padzero(floor(secs),2);
milli := floor( (1000*fn/rate)) mod 6000 mod 1000;
millistr := padzero(floor(milli),3);
result := hoursStr +':'+ minsStr +':'+ secsStr +'.'+ milliStr;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
edit2.text := frameNo2timecode(strToint(edit1.text), 29.970);
end;
end.
I am using Delphi 2010, latest version (from repository) of JEDI WinAPI and Windows Security Code Library (WSCL).
I don't know how to call the NetUserSetGroups function. The way I am doing it, it is throwing an exception:
Access violation at address 5B8760BE
in module 'netapi32.dll'. Write of
address 00000000.
Following is my code:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, JwaWindows, JwsclSid;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
NetApiStatus: NET_API_STATUS;
dwEntriesRead, dwEntriesTotal: PDWORD;
lgi01: LOCALGROUP_USERS_INFO_0;
username: PChar;
begin
username := 'Elise';
NetApiStatus := NetUserGetLocalGroups(nil, PChar(username), 0, LG_INCLUDE_INDIRECT, PByte(lgi01),
MAX_PREFERRED_LENGTH, dwEntriesRead, dwEntriesTotal);
if NetApiStatus = NERR_SUCCESS then
showmessage('Total groups user belongs to: ' + IntTostr(dwEntriesTotal^));
end;
end.
Would appreciate if someone could kindly show me how I can call this function?
Thanks in advance.
This code works fine for me:
type
LocalGroupUsersInfo0Array = array[0..ANYSIZE_ARRAY-1] of LOCALGROUP_USERS_INFO_0;
PLocalGroupUsersInfo0Array = ^LocalGroupUsersInfo0Array;
procedure TForm3.Button3Click(Sender: TObject);
var
nas: NET_API_STATUS;
PLGUIA: PLocalGroupUsersInfo0Array;
Count: DWORD;
Total: DWORD;
i: Integer;
begin
PLGUIA := nil;
nas := NetUserGetLocalGroups(nil, PChar('rweijnen'), 0, LG_INCLUDE_INDIRECT,
PByte(PLGUIA), MAX_PREFERRED_LENGTH, #Count, #Total);
if (nas = NERR_Success) or (nas = ERROR_MORE_DATA) then
begin
for i := 0 to Count - 1 do
begin
Memo1.Lines.Add(Format('name=%s', [PLGUIA^[i].lgrui0_name]));
end;
if Assigned(PLGUIA) then
NetApiBufferFree(PLGUIA);
end;
end;