We have a legacy Delphi application which uses IcmpSendEcho (from iphlpapi.dll) to perform echo requests. As I understand it, this performs the same function as "ping" from the command prompt.
On Windows XP, the code below works fine. When the IPv4 address is correct the response is quick and if not error code 11010 (IP_REQ_TIMED_OUT) is returned as expected.
However, on my 32-bit Windows 10 machine, the error code is 87 (ERROR_INVALID_PARAMETER). I've carefully reviewed the Microsoft documentation for IcmpSendEcho and cannot see anything obvious that is wrong.
"ping 200.1.2.121" (the example IPv4 address I use in the code sample) works as expected from the command prompt in both XP and 10.
type
PIpAddress = ^TIpAddress;
TIpAddress = record
case Integer of
0: (S_un_b: TSunB);
1: (S_un_w: TSunW);
2: (S_addr: LongWord);
end;
IpAddress = TIpAddress;
// Functions imported from external DLLs
function IcmpCreateFile() : THandle; stdcall; external 'iphlpapi.dll';
function IcmpCloseHandle(icmpHandle: THandle) : Boolean; stdcall; external 'iphlpapi.dll';
function IcmpSendEcho(IcmpHandle: THandle; ipDest: IpAddress;
pRequestData: Pointer; nRequestSize: SmallInt; RequestOptions: Pointer;
pReplyBuffer: Pointer; dwReplySize: DWORD; dwTimeout: DWORD) : DWORD; stdcall; external 'iphlpapi.dll';
procedure TranslateStringToIpAddress(strIP: String; var ipAddress);
var
phe: PHostEnt;
pac: PChar;
begin
try
phe := GetHostByName(PChar(strIP));
if (Assigned(phe)) then
begin
pac := phe^.h_addr_list^;
if (Assigned(pac)) then
begin
with TIpAddress(ipAddress).S_un_b do
begin
by1 := Byte(pac[0]);
by2 := Byte(pac[1]);
by3 := Byte(pac[2]);
by4 := Byte(pac[3]);
end;
end
else
begin
raise Exception.Create('Error getting IP from HostName');
end;
end
else
begin
raise Exception.Create('Error getting HostName');
end;
except
FillChar(ipAddress, SizeOf(ipAddress), #0);
end;
end;
function Ping(strIpAddress : String) : Boolean;
const
ICMP_ECHO_BUFFER = 128; // Works as low as 28 on Windows XP (nothing works on Windows 10)
var
address: IpAddress;
dwReplies: DWORD;
{$IFDEF DBG} dwErrorCode: DWORD; {$ENDIF}
abyReplyBuffer: array[1..ICMP_ECHO_BUFFER] of BYTE;
begin
// Use this function to determine if an IPv4 address can be reached
Result := False;
// "m_cache.hPingHandle" is generated earlier with a call to "IcmpCreateFile"
if (m_cache.hPingHandle = INVALID_HANDLE_VALUE) then
Exit;
TranslateStringToIpAddress(strIpAddress, address);
dwReplies := IcmpSendEcho(
m_cache.hPingHandle, address, nil, 0, nil, #abyReplyBuffer, ICMP_ECHO_BUFFER, 0);
{$IFDEF DBG}
if (dwReplies = 0) then
begin
dwErrorCode := GetLastError();
// dwErrorCode = 87 (ERROR_INVALID_PARAMETER, "The parameter is incorrect")
Application.MessageBox(
PAnsiChar(Format('WinError = %d', [dwErrorCode])), 'Ping failed', MB_ICONEXCLAMATION);
end;
{$ENDIF}
// Success?
Result := (dwReplies <> 0);
end;
// Usage elsewhere in the application...
Ping('200.1.2.121'); // Works on Windows XP, but fails on Windows 10
Based on the comment from #FredS (thanks!), the answer is simply to make the last parameter for the IcmpSendEcho non-zero (eg. "200").
The MSDN documentation for IcmpSendEcho does not make this clear, so Microsoft have probably changed the internal implementation of this method from the version in Windows XP so that a non-zero Timeout is now required.
Related
Good afternoon,
I need lock CTRL+ALT+DEL combination using SetWindowsHookEx and today i have done a code and don't is working until now.
This code is executing in a dll ( this dll is my software ) that is injected in other process.
So, how i can adapt this code below to work?
const
WH_KEYBOARD_LL = 13;
LLKHF_ALTDOWN = $20;
type
KBDLLHOOKSTRUCT = record
vkCode: DWORD;
scanCode: DWORD;
flags: DWORD;
time: DWORD;
dwExtraInfo: Longint ;
end;
var
hhkLowLevelKybd : HHOOK;
FoldProc : LongInt;
hSASWnd : HWND;
hThread : Cardinal;
{$R *.dfm}
Function LowLevelKeyboardProc(nCode : Integer; wParam : Longint; var LParam: KBDLLHOOKSTRUCT) : Longint; stdcall;
var
fEatKeystroke : Boolean;
dwThreadId : Cardinal;
begin
If (nCode = HC_ACTION) Then
begin
If (wParam = WM_KEYDOWN) Or
(wParam = WM_SYSKEYDOWN) Or
(wParam = WM_KEYUP) Or
(wParam = WM_SYSKEYUP) Then
begin
fEatKeystroke :=
(((GetKeyState(VK_CONTROL) And $8000) <> 0) And
((LParam.flags And LLKHF_ALTDOWN ) <> 0) And
(LParam.vkCode = VK_DELETE));
End;
If fEatKeystroke Then
Result := -1
Else
Result := CallNextHookEx(0, nCode, wParam, LongInt(#LParam));
End;
end;
////////// FormCreate event here ///////////
hhkLowLevelKybd := 0;
hhkLowLevelKybd := SetWindowsHookEx(WH_KEYBOARD_LL, #LowLevelKeyboardProc,
HInstance, 0);
end.
Windows does not allow you to intercept Ctrl+Alt+Del for security reasons. Earlier versions (pre-Vista?) used to allow it by replacing the GINA DLL, but it's not been allowed for years.
That key combination is known as a secure attention sequence which is guaranteed to be trustworthy as part of the login process.
If your goal is to only allow your application to be run, you can configure it to act in kiosk mode if you're running a suitable version of Windows, as shown in Set up a device for anyone to use (kiosk mode) at TechNet which #LURD kindly provided.
By design it's impossible to trap or block Ctrl+Alt+Del (The Secure Attention Sequence). There is however a commercial library available (disclaimer: I am the author), SasLibEx.
SasLibEx: a library that can simulate or block the Secure Attention
Sequence (Ctrl+Alt+Del) but it can even unlock a
workstation or session without entering or needing the user’s
credentials (and many more things)
See this screencast for a demo.
Impossible. The Ctl-Alt-Del gets trapped in the Kernel and never makes it to the user mode space where your app is running.
I have had to do this on kiosks systems (using Win XP and Vista) and I did it with a keyboard filter driver (which runs in the kernel) that swaps out the scan codes when the key are pressed.
Not is impossible, see the following code:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils,
Windows,
Registry,
vcl.Dialogs;
procedure DisableCtrAltDel(boolState: Boolean);
var
SystemReg: TRegistry;
Data: Array [1 .. 48] of Byte;
i: Byte;
begin
try
for i := 1 to 48 do
Data[i] := $00;
Data[9] := $09;
Data[15] := $5B;
Data[16] := $E0;
Data[19] := $5C;
Data[20] := $E0;
Data[23] := $5D;
Data[24] := $E0;
Data[27] := $44;
Data[31] := $1D;
Data[35] := $38;
Data[39] := $1D;
Data[40] := $E0;
Data[43] := $38;
Data[44] := $E0;
try
SystemReg := TRegistry.Create;
with SystemReg do
begin
RootKey := HKEY_LOCAL_MACHINE;
OpenKey('\System\CurrentControlSet\Control\Keyboard Layout', True);
if boolState then
WriteBinaryData('Scancode Map', Data, SizeOf(Data))
else
DeleteValue('Scancode Map');
MessageDlg('Restart Windows in order the changes to take effect!',
mtInformation, [mbOK], 0);
CloseKey;
end;
finally
SystemReg.Free;
end;
except
MessageDlg
('Error occurred while trying to disable ctrl+alt+del and Task Manager',
mtWarning, [mbOK], 0);
end;
end;
begin
try
DisableCtrAltDel(True);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Reference
I just bought a NFC ACR122U.
It comes with samples to delphi 7.
I am using delphi XE8 and compiling the sample to 32 bits/win 8.1.
I did the correct changes(I believe) to adapt the api and sample project functions to delphi Xe8, replacing Pchar to PAnsiChar and Char to AnsiChar where needed.
I am using native win 8 drivers, no manufacturer drive.
I can initialize the device and get the device name correctly with:
procedure TfrmDevProg.btnInitClick(Sender: TObject);
var index: integer;
begin
//Establish context
retCode := SCardEstablishContext(SCARD_SCOPE_USER,
nil,
nil,
#hContext);
if retCode <> SCARD_S_SUCCESS then begin
displayout(GetScardErrMsg(retcode),2);
Exit;
end ;
//List PC/SC readers installed in the system
BufferLen := MAX_BUFFER_LEN;
retCode := SCardListReadersA(hContext,
nil,
#Buffer,
#BufferLen);
if retCode <> SCARD_S_SUCCESS then begin
DisplayOut(getscarderrmsg(retCode),2);
Exit;
end;
btnInit.Enabled := false;
btnConnect.Enabled := true;
LoadListToControl(cbReader,#buffer,bufferLen);
// Look for ACR128 PICC and make it the default reader in the combobox
for index := 0 to cbReader.Items.Count-1 do begin
cbReader.ItemIndex := index;
if AnsiPos('ACR122U PICC', cbReader.Text) > 0 then
Exit;
end;
cbReader.ItemIndex := 0;
end;
The procedure above works very well. Next, I use the next code to connect to device:
procedure TfrmDevProg.btnConnectClick(Sender: TObject);
begin
//Connect to reader using a shared connection
retCode := SCardConnectA(hContext,
PAnsiChar(cbReader.Text),
SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 or SCARD_PROTOCOL_T1,
#hCard,
#dwActProtocol);
if retcode <> SCARD_S_SUCCESS then begin
displayout(GetScardErrMsg(retcode),2)
end
else begin
displayout('Successful connection to ' + cbReader.Text, 1)
end;
end;
Here, I am getting an error from SCardConnectA: "The specified reader name is not recognized." and the retcode var is: -2146435063.
Here is a snippet code of the api copied from DVD sent with the device, when I bought it:
///////////////////////////////////////////////////////////////////////////////
// Imported functions from Winscard.dll (WIN32 API)
///////////////////////////////////////////////////////////////////////////////
Function SCardEstablishContext(dwscope :DWORD;
pvReserved1: LPCVOID;
pvReserved2: LPCVOID;
phContext :LPSCARDCONTEXT):LONG; stdcall; external 'Winscard.dll';
Function SCardReleaseContext(hContext:SCARDCONTEXT):LONG; stdcall; external 'Winscard.dll';
Function SCardListReadersA(hContext : SCARDCONTEXT;
mszGroups:LPCSTR;
szReaders:LPSTR;
pcchReaders:LPDWORD):LONG; stdcall; external 'Winscard.dll';
//Note : ScardConnectA is for non-UNICODE characters which is only one byte.
// For UNICODE characters it is SCardConnectW. Special processing is
// required for UNICODE. Be careful!
Function SCardConnectA(hContext : SCARDCONTEXT;
szReaders:LPSTR;
dwShareMode : DWORD;
dwPreferredProtocols : DWORD;
phCard : LPSCARDHANDLE;
pdwActiveProtocols:LPDWORD):LONG; stdcall; external 'Winscard.dll';
I downloaded an binary app from mannufacturer site to test the device and all works well. But I need do it work with my Delphi app.
Any help, please.
the problem is the cast from cbReader.Text do PAnsiChar.
fix it to
retCode := SCardConnectA(hContext, PAnsiChar(AnsiString(cbReader.Text)), SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 or SCARD_PROTOCOL_T1, #hCard, #dwActProtocol);
i have Call Center Using Avaya System I need To manage this System
by my application that's developed by my
there are dll Called devlink have 4 Events
DEVLINK_COMMS_OPERATIONAL
DEVLINK_COMMS_NORESPONSE
DEVLINK_COMMS_REJECTED
DEVLINK_COMMS_MISSEDPACKETS
the first Event
DEVLINK_COMMS_OPERATIONAL
meen the connection was establish
when Click The Button Connect
procedure TfrmMain.btnConnectClick(Sender: TObject);
var
hEvent:integer;
vPass,vAddress:PChar;
begin
with frmSetup.tblConnections do
begin
First;
while not Eof do
begin
if FieldByName('IPEnabled').AsInteger=1 then
Begin
vPass:=PChar(FieldByName('IPPassword').AsString);
vAddress:=PChar(FieldByName('IpAddress').AsString);
DLOpen(fNextHandle, vAddress,vPass, nil, nil,HandleCommsEvent);
Edit;
FieldByName('pbxh').AsInteger:=fNextHandle;
Post;
hEvent := CreateEvent(nil, FALSE, FALSE, nil);
try
WaitForSingleObject(hEvent, 10000);
if (Locate('pbxh',fNextHandle,[]))and(FieldByName('connected').AsInteger=1) then
else
LogAddLine(fNextHandle,'No Responce');
finally
CloseHandle(hEvent);
inc(fNextHandle);
end;
End;
next;
end;
end;
end;
we note DlOpen Method Take the IP of system And Password
and Event that will fire to test the Dlopen
Always appear message of the event DEVLINK_COMMS_NORESPONSE
that is no response
i need to know where the error where the IP And Password Was correct. There
are The HandleCommsEvent
procedure HandleCommsEvent(pbxh: LongInt; Comms_status: DWORD; Parm1: DWORD);stdcall;
stdcall;
begin
//4 cases for event of DLOPEN
LogAddLine(pbxh,'HandleCommsEvent happend');
case Comms_status of
DEVLINK_COMMS_OPERATIONAL:
Begin
DLRegisterType2CallDeltas(pbxh, HandleEvent);
LogAddLine(pbxh,'Connected Done');
if frmSetup.tblConnections.Locate('pbxh',pbxh,[]) then
Begin
frmSetup.tblConnections.Edit;
frmSetup.tblConnections.FieldByName('connected').AsInteger:=1;
frmSetup.tblConnections.Post;
End;
end;
DEVLINK_COMMS_NORESPONSE:
begin
LogAddLine(pbxh,'Connected NORESPONSE There Are Problem In network ');
if frmSetup.tblConnections.Locate('pbxh',pbxh,[]) then
Begin
frmSetup.tblConnections.Edit;
frmSetup.tblConnections.FieldByName('pbxh').AsInteger:=pbxh;
frmSetup.tblConnections.FieldByName('connected').AsInteger:=0;
frmSetup.tblConnections.Post;
End;
end ;
DEVLINK_COMMS_REJECTED:
begin
LogAddLine(pbxh,'Connected REJECTED,Password was incorrect');
if frmSetup.tblConnections.Locate('pbxh',pbxh,[]) then
Begin
frmSetup.tblConnections.Edit;
frmSetup.tblConnections.FieldByName('pbxh').AsInteger:=pbxh;
frmSetup.tblConnections.FieldByName('connected').AsInteger:=0;
frmSetup.tblConnections.Post;
End;
end;
// Case of Packets were generated by IP Office System unit ,but Not recieved by Devlink
DEVLINK_COMMS_MISSEDPACKETS:
begin
LogAddLine(pbxh,'Connected MISSEDPACKETS ,Packets were generated by IP Office System unit ,but Not recieved by Devlink ');
end;
//Case of NO Response from From System Unit
end;
end;
if Any one need more info and details i'm ready.
The Message of NO Response Always appear
for more Details
This is Devlink
unit UDevLink;
{**************************************************************************}
{ Delphi unit for DevLink (c) 2001 Avaya Global SME Solutions }
{ Contents:- }
{ IP Office DevLink DLL provides an interface for managing }
{ the IP Office product ranges from a Windows PC }
{**************************************************************************}
interface
uses
Windows, SysUtils , Classes, UfrmMain,strutils,Ustrings;
const
DEVLINK_SUCCESS = 0;
DEVLINK_UNSPECIFIEDFAIL = 1;
DEVLINK_LICENCENOTFOUND = 2;
const
DEVLINK_COMMS_OPERATIONAL = 0;
DEVLINK_COMMS_NORESPONSE = 1;
DEVLINK_COMMS_REJECTED = 2;
DEVLINK_COMMS_MISSEDPACKETS = 3;
type
TCallLogEvent = procedure(pbxh: LongInt; info: PChar); stdcall;
type
TCommsEvent = procedure(pbxh: LongInt;
Comms_status: DWORD;
Parm1: DWORD); stdcall;
function DLOpen(pbxh: LongInt;
pbx_address: PChar;
pbx_password: PChar;
reserved1: PChar;
reserved2: PChar;
cb: TCommsEvent): LongInt; stdcall;
function DLClose(pbxh: THandle): LongInt; stdcall;
function DLRegisterType2CallDeltas(pbxh: LongInt;
cb: TCallLogEvent): LongInt; stdcall;
implementation
function DLOpen; external 'DEVLINK.DLL';
function DLClose; external 'DEVLINK.DLL';
function DLRegisterType2CallDeltas; external 'DEVLINK.DLL';
end.
Your DB management is manipulating the DB cursor while you are iterating with the same cursor. There is no need to Locate() the record that you are actively processing.
Your call to DlOpen() should look more like this, based on the Delphi example provided in the official Avaya DevLink API documentation (which I assume you have read):
var
hEvent: THandle;
Status: DWORD;
Starting: Boolean;
procedure HandleCommsEvent(pbxh: LongInt; Comms_status: DWORD; Parm1: DWORD); stdcall;
begin
//4 cases for event of DLOPEN
LogAddLine(pbxh, 'HandleCommsEvent happend');
case Comms_status of
DEVLINK_COMMS_OPERATIONAL,
DEVLINK_COMMS_NORESPONSE,
DEVLINK_COMMS_REJECTED:
begin
if Starting then begin
Status := Comms_status;
SetEvent(hEvent);
end;
end;
// Case of Packets were generated by IP Office System unit ,but Not recieved by Devlink
DEVLINK_COMMS_MISSEDPACKETS:
begin
LogAddLine(pbxh,'Connected MISSEDPACKETS ,Packets were generated by IP Office System unit ,but Not recieved by Devlink ');
end;
//Case of NO Response from From System Unit
end;
end;
procedure TfrmMain.btnConnectClick(Sender: TObject);
var
vPass, vAddress: String;
begin
hEvent := CreateEvent(nil, TRUE, FALSE, nil);
try
with frmSetup.tblConnections do
begin
First;
while not Eof do
begin
if FieldByName('IPEnabled').AsInteger = 1 then
begin
vPass := FieldByName('IPPassword').AsString;
vAddress := FieldByName('IpAddress').AsString;
Edit;
FieldByName('pbxh').AsInteger := fNextHandle;
FieldByName('connected').AsInteger := 0;
Post;
Status := DEVLINK_COMMS_NORESPONSE;
Starting := True;
ResetEvent(hEvent);
DLOpen(fNextHandle, PChar(vAddress), PChar(vPass), nil, nil, HandleCommsEvent);
WaitForSingleObject(hEvent, 10000);
Starting := False;
if Status = DEVLINK_COMMS_OPERATIONAL then
begin
DLRegisterType2CallDeltas(fNextHandle, HandleEvent);
LogAddLine(fNextHandle, 'Connected Done');
Edit;
FieldByName('connected').AsInteger := 1;
Post;
end else
begin
DLClose(fNextHandle);
case Status of
DEVLINK_COMMS_NORESPONSE:
begin
LogAddLine(fNextHandle, 'Connected NORESPONSE There Are Problem In network ');
end;
DEVLINK_COMMS_REJECTED:
begin
LogAddLine(fNextHandle, 'Connected REJECTED,Password was incorrect');
end;
end;
end;
end;
Inc(fNextHandle);
end;
Next;
end;
finally
CloseHandle(hEvent);
end;
end;
upload logs for more details..
and write else part of case to check value of Comms_status
I’ve created a local COM server that requires elevation and should be instantiated from inside a non-elevated process.
Using MSDN's article on the COM elevation moniker, I’ve configured the server class following the specified requirements. The server was successfully registered in the HKLM hive.
The code sample:
procedure CoCreateInstanceAsAdmin(const Handle: HWND;
const ClassID, IID: TGuid; PInterface: PPointer);
var
rBindOpts: TBindOpts3;
sMonikerName: WideString;
iRes: HRESULT;
begin
ZeroMemory(#rBindOpts, Sizeof(TBindOpts3));
rBindOpts.cbStruct := Sizeof(TBindOpts3);
rBindOpts.hwnd := Handle;
rBindOpts.dwClassContext := CLSCTX_LOCAL_SERVER;
sMonikerName := 'Elevation:Administrator!new:' + GUIDToString(ClassID);
iRes := CoGetObject(PWideChar(sMonikerName), #rBindOpts, IID, PInterface);
OleCheck(iRes);
end;
class function CoIMyServer.Create: IMyServer;
begin
CoCreateInstanceAsAdmin(HInstance, CLASS_IMyServer, IMyServer, #Result);
end;
When it comes to CoGetObject(PWideChar(sMonikerName), #rBindOpts, IID, PInterface) I get the UAC screen and confirm running the server as admin. However, OleCheck(iRes) returns: "The requested operation requires elevation" error.
From that article I’ve read about "Over-The-Shoulder (OTS) Elevation".
Is this the only way to get my server instance available for the non-elevated process? If so, when should CoInitializeSecurity be called on the server?
Complete registration details
HKLM\SOFTWARE\Wow6432Node\Classes\CLSID
{MyServer CLSID}
(Default) = IMyServer Object
LocalizedString = #C:\Program Files (x86)\MyServer\MyServer.exe,-15500
Elevation
Enabled = 0x000001 (1)
LocalServer32
(Default) = C:\PROGRA~2\MyServer\MYSERVER.EXE
ProgID
(Default) = uMyServer.IMyServer
TypeLib
(Default) = {TypeLib GUID}
Version
(Default) = 1.0
HKLM\SOFTWARE\Wow6432Node\Classes\Interface
{GUID of IID_IMyServer}
(Default) = IMyServer
ProxyStubClsid32
(Default) = {Some GUID}
TypeLib
(Default) = {TypeLib GUID}
Version = 1.0
Above are the only entries that exist in my registry after registering the server.
Additional details
Tried without success calling CoInitializeSecurity() implicitly + setting lunch permissions as advised using the following code:
function GetSecurityDescriptor(const lpszSDDL: LPWSTR; out pSD: PSecurityDescriptor): Boolean;
begin
Result := ConvertStringSecurityDescriptorToSecurityDescriptorW(lpszSDDL, SDDL_REVISION_1,
pSD, nil);
end;
function GetLaunchActPermissionsWithIL(out pSD: PSecurityDescriptor): Boolean;
var
lpszSDDL: LPWSTR;
begin
// Allow World Local Launch/Activation permissions. Label the SD for LOW IL Execute UP
lpszSDDL := 'O:BAG:BAD:(A;;0xb;;;WD)S:(ML;;NX;;;LW)';
Result := GetSecurityDescriptor(lpszSDDL, pSD);
end;
function GetAccessPermissionsForLUAServer(out pSD: PSecurityDescriptor): Boolean;
var
lpszSDDL: LPWSTR;
begin
// Local call permissions to IU, SY
lpszSDDL := 'O:BAG:BAD:(A;;0x3;;;IU)(A;;0x3;;;SY)';
Result := GetSecurityDescriptor(lpszSDDL, pSD);
end;
function SetAccessPermissions(hAppKey: HKEY; pSD: PSECURITY_DESCRIPTOR): Boolean;
var
dwLen: DWORD;
iRes: LONG;
begin
dwLen := GetSecurityDescriptorLength(pSD);
iRes := RegSetValueExA(hAppKey, 'AccessPermission', 0, REG_BINARY, pSD, dwLen);
Result := iRes = ERROR_SUCCESS;
end;
function SetLaunchActPermissions(hAppKey: HKEY; pSD: PSECURITY_DESCRIPTOR): Boolean;
var
dwLen: DWORD;
iRes: LONG;
begin
dwLen := GetSecurityDescriptorLength(pSD);
iRes := RegSetValueExA(hAppKey, 'LaunchPermission', 0, REG_BINARY, pSD, dwLen);
Result := iRes = ERROR_SUCCESS;
end;
procedure Initialize;
var
pSD: PSecurityDescriptor;
sSubKey: WideString;
hAppKey: HKEY;
begin
sSubKey := 'AppID\{GUID}';
RegOpenKeyW(HKEY_CLASSES_ROOT, PWideChar(sSubKey), hAppKey);
if GetAccessPermissionsForLUAServer(pSD) then
if not SetAccessPermissions(hAppKey, pSD) then
raise Exception.Create(Format('Access permissions aren''t set. System error: %d',
[GetLastError()]));
pSD := nil;
if GetLaunchActPermissionsWithIL(pSD) then
if not SetLaunchActPermissions(hAppKey, pSD) then
raise Exception.Create(Format('Launch permissions aren''t set. System error: %d',
[GetLastError()]));
end;
initialization
TAutoObjectFactory.Create(ComServer, TMyServer, Class_IMyServer,
ciMultiInstance, tmApartment);
Initialize;
As a AppID GUID I tried to use both the same CLSID GUID of my server interface and a new generated GUID: result was the same.
AccessPermission and LaunchPermission values appeared at the specified place after server registering.
Also tried:
Specifying ROTFlags = 1 in the AppId key
Building the server as 64-bit application
Additional registry keys/values I created manually:
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\MyServer.exe]
#="MyServer"
"AppID"="{My GUID}"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{My GUID}]
#="MyServer"
"ROTFlags"=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{My GUID}]
#="MyServer Object"
"AppID"="{My GUID}"
One mistake you are making is you are passing the RTL's global HInstance variable where CoGetObject() expects an HWND instead. An HINSTANCE handle is not a valid HWND handle. You need to use an actual HWND such as the Handle property of a TForm, or else specify 0 to let the Elevation Moniker choose a suitable window for you.
As for the ERROR_ELEVATION_REQUIRED return value, all I can say is that your COM registration is likely incomplete somewhere. Please show the complete registration details that are actually being stored in the Registry (not what your code thinks it is storing - what the Registry is actually storing).
CoInitializeSecurity() should be called when the server process begins running.
Lets assume you have a app that opens a socket port for communication purposes. How can I get the path of this app only by knowing its port?
I want to do what netstat -b does. It lists all socket ports opened and the app that opened the socket.
I am using delphi 2010.
By knowing which app opened which port I am able to kill the app.
Note that I need a delphi code, not an Dos command or an explanation of how to use netstat.
Rafael, you can use the GetExtendedTcpTable function, this function retrieves a table that contains a list of TCP connections availables.
first you must inspect the records returned by this function, and check the dwLocalPortor dwRemotePort (depending of what port your need to check), then you can get the pid of the application checking the dwOwningPid field and resolve the exe name using a windows api function like GetModuleFileNameEx
Check this sample application which show all tcp connections like netstat. you can modify this sample to fit with your requirements.
uses
PsAPI,
WinSock,
Windows,
SysUtils;
const
ANY_SIZE = 1;
iphlpapi = 'iphlpapi.dll';
TCP_TABLE_OWNER_PID_ALL = 5;
MIB_TCP_STATE:
array[1..12] of string = ('CLOSED', 'LISTEN', 'SYN-SENT ','SYN-RECEIVED', 'ESTABLISHED', 'FIN-WAIT-1',
'FIN-WAIT-2', 'CLOSE-WAIT', 'CLOSING','LAST-ACK', 'TIME-WAIT', 'delete TCB');
type
TCP_TABLE_CLASS = Integer;
PMibTcpRowOwnerPid = ^TMibTcpRowOwnerPid;
TMibTcpRowOwnerPid = packed record
dwState : DWORD;
dwLocalAddr : DWORD;
dwLocalPort : DWORD;
dwRemoteAddr: DWORD;
dwRemotePort: DWORD;
dwOwningPid : DWORD;
end;
PMIB_TCPTABLE_OWNER_PID = ^MIB_TCPTABLE_OWNER_PID;
MIB_TCPTABLE_OWNER_PID = packed record
dwNumEntries: DWord;
table: array [0..ANY_SIZE - 1] OF TMibTcpRowOwnerPid;
end;
var
GetExtendedTcpTable:function (pTcpTable: Pointer; dwSize: PDWORD; bOrder: BOOL; lAf: ULONG; TableClass: TCP_TABLE_CLASS; Reserved: ULONG): DWord; stdcall;
function GetPathPID(PID: DWORD): string;
var
Handle: THandle;
begin
Result := '';
Handle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID);
if Handle <> 0 then
try
SetLength(Result, MAX_PATH);
if GetModuleFileNameEx(Handle, 0, PChar(Result), MAX_PATH) > 0 then
SetLength(Result, StrLen(PChar(Result)))
else
Result := '';
finally
CloseHandle(Handle);
end;
end;
procedure ShowCurrentTCPConnections;
var
Error : DWORD;
TableSize : DWORD;
i : integer;
IpAddress : in_addr;
RemoteIp : string;
LocalIp : string;
FExtendedTcpTable : PMIB_TCPTABLE_OWNER_PID;
begin
TableSize := 0;
Error := GetExtendedTcpTable(nil, #TableSize, False, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
if Error <> ERROR_INSUFFICIENT_BUFFER then
Exit;
GetMem(FExtendedTcpTable, TableSize);
try
if GetExtendedTcpTable(FExtendedTcpTable, #TableSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0) = NO_ERROR then
for i := 0 to FExtendedTcpTable.dwNumEntries - 1 do
if {(FExtendedTcpTable.Table[i].dwOwningPid=Pid) and} (FExtendedTcpTable.Table[i].dwRemoteAddr<>0) then //here you can check the particular port
begin
IpAddress.s_addr := FExtendedTcpTable.Table[i].dwRemoteAddr;
RemoteIp := string(inet_ntoa(IpAddress));
IpAddress.s_addr := FExtendedTcpTable.Table[i].dwLocalAddr;
LocalIp := string(inet_ntoa(IpAddress));
Writeln(GetPathPID(FExtendedTcpTable.Table[i].dwOwningPid));
Writeln(Format('%-16s %-6d %-16s %-6d %s',[LocalIp,FExtendedTcpTable.Table[i].dwLocalPort,RemoteIp,FExtendedTcpTable.Table[i].dwRemotePort,MIB_TCP_STATE[FExtendedTcpTable.Table[i].dwState]]));
end;
finally
FreeMem(FExtendedTcpTable);
end;
end;
var
libHandle : THandle;
begin
try
ReportMemoryLeaksOnShutdown:=DebugHook<>0;
libHandle := LoadLibrary(iphlpapi);
GetExtendedTcpTable := GetProcAddress(libHandle, 'GetExtendedTcpTable');
ShowCurrentTCPConnections;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.
You can use IP Helper Component of Magenta Systems.
It is free and also has very good example
For correct number of port you must using function WinSock
ntohs(FExtendedTcpTable.Table[i].dwLocalPort)