In Delphi, using WinAPI, I am try to get list of groups that have permission to file or folder, example group list:
What function or records I need to use to get these information?
I am try to using GetNamedSecurityInfoA but it fails - function return false and variables sidGrp with dacl are still nil, but variable sc (Security Descriptor) is initialized.
procedure TForm1.Button2Click(Sender: TObject);
var
sciezka: array [0 .. 256] of ansiChar;
sidOwn: PSID;
sidGrp: PSID;
dacl: PACL;
sacl: PACL;
sc: PSECURITY_DESCRIPTOR;
success: DWORD;
access: EXPLICIT_ACCESS_A;
sid_id_auth: _SID_IDENTIFIER_AUTHORITY;
hToken: THandle;
TokenUserPoint: pTokenUser;
bufferSize: DWORD;
BufferSize2: DWORD;
ptgGroups: PTokenGroups;
psidAdmin: PSID;
x: Integer;
const
SECURITY_NT_AUTHORITY: TSidIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
begin
Memo1.Lines.Clear();
ZeroMemory(#sciezka, Length(sciezka));
GetMem(ptgGroups, 1024);
bufferSize := 0;
System.AnsiStrings.StrLCopy(#sciezka, PAnsiChar(AnsiString(Edit1.Text)), Length(Edit1.Text));
// success := CheckFileAccess(string(sciezka), FILE_READ_DATA);
success := Cardinal(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY OR TOKEN_READ, hToken));
success := Cardinal(GetTokenInformation(hToken, TokenUser, ptgGroups, 1024, bufferSize));
GetMem(TokenUserPoint, BYTE(bufferSize));
//FillChar(TokenUserPoint, bufferSize, 0);
//success := Cardinal(GetTokenInformation(hToken, TokenUser, TokenUserPoint, bufferSize, BufferSize2));
sidOwn := nil;
sidGrp := nil;
dacl := nil;
sacl := nil;
sc := nil;
sid_id_auth.Value[0] := 2;
sid_id_auth.Value[1] := 3;
sid_id_auth.Value[2] := 5;
sid_id_auth.Value[3] := 0;
sid_id_auth.Value[4] := 0;
sid_id_auth.Value[5] := 0;
success := Cardinal(AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2, SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, psidAdmin));
{$R-}
{ for x := 0 to ptgGroups.GroupCount - 1 do
if EqualSid(psidAdmin, ptgGroups.Groups[x].Sid) then
begin
Memo1.Lines.Add('Jest administrator');
Break;
end; }
{$R+}
// success := GetFileSecurityA(sciezka, GROUP_SECURITY_INFORMATION, sc, );
success := GetNamedSecurityInfoA(sciezka,
SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION or GROUP_SECURITY_INFORMATION or DACL_SECURITY_INFORMATION,
nil,
sidGrp,
dacl,
nil,
sc
);
Memo1.Lines.Add('Funkcja zwróciła wartoć = ' + success.ToHexString());
if IsValidSid(sidOwn) then Memo1.Lines.Add('sidOwn - poprawne')
else Memo1.Lines.Add('sidOwn - niepoprawne');
if IsValidSid(sidGrp) then Memo1.Lines.Add('sidGrp - poprawne')
else Memo1.Lines.Add('sidGrp - niepoprawne');
if(sidOwn = nil) then
Memo1.Lines.Add('sidOwn is null');
if(sidGrp = nil) then
Memo1.Lines.Add('sidGrp is null');
end;
As #FredS said, the parameters use pointer of pointer, and you declare here:
sidGrp: PSID;
Dacl: PACL;
Sacl: PACL;
sidGrp := nil;
dacl := nil;
sacl := nil;
sc: PSECURITY_DESCRIPTOR;
success := GetNamedSecurityInfoA(sciezka,
SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION or GROUP_SECURITY_INFORMATION or DACL_SECURITY_INFORMATION,
nil,
sidGrp,
dacl,
nil,
sc
);
which is equal to:
success := GetNamedSecurityInfoA(sciezka,
SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION or GROUP_SECURITY_INFORMATION or DACL_SECURITY_INFORMATION,
nil,
nil,
nil,
nil,
nil
);
And you will get the return error: 87(ERROR_INVALID_PARAMETER)
According to the function document:
success := GetNamedSecurityInfoA(sciezka,
SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION or GROUP_SECURITY_INFORMATION or DACL_SECURITY_INFORMATION,
nil,
#sidGrp,
#dacl,
nil,
sc
);
Related
I'm trying to use cuda hardware accelerated video decoding, loading from a .mp4 file, according to the code bellow, but getting the image with shadows
Specification:
FFMPEG 4.3
Delphi 10.3
NVIDIA GeForce RTX 3050 Laptop GPU 4Gb DDR6
Intel Core i5 11400H 16 Gb RAM
unit UVideoDecoding;
interface
uses
Vcl.Graphics, Winapi.Windows,
System.SysUtils, System.Classes,
libavcodec, libavdevice,
libavfilter, libswresample, libavformat, libavutil,
libswscale;
type
TDecoder = class
protected
fFormatCtx: PAVFormatContext;
fCodec: PAVCodec;
fCodecParams, fLocalCodecParams: PAVCodecParameters;
fCodecCtx: libavcodec.PAVCodecContext;
fPacket: PAVPacket;
fFrameIn, fFrameOut: PAVFrame;
fScaler: PSwsContext;
fVideoStreamIndex: Integer;
fHWPixelFormat: AVPixelFormat;
fOutputWidth: Integer;
fOutputHeight: Integer;
function DecodeVideoPacket: Integer;
public
function Load(pFileName: string): Integer;
end;
implementation
function TDecoder.Load(pFileName: string): Integer;
var
vCount: Integer;
vLocalCodec: PAVCodec;
vFileName: AnsiString;
vType: AVHWDeviceType;
vDecPackResponse: Integer;
begin
vType := av_hwdevice_find_type_by_name('cuda');
{vType = AV_HWDEVICE_TYPE_CUDA}
fFormatCtx := avformat_alloc_context;
vFileName := AnsiString(pFileName);
avformat_open_input(fFormatCtx, PAnsiChar(vFileName), nil, nil);
avformat_find_stream_info(fFormatCtx, nil);
for vCount := 0 to fFormatCtx.nb_streams - 1 do
begin
fLocalCodecParams := fFormatCtx.streams[vCount].codecpar;
case fLocalCodecParams.codec_id of
AVCodecID.AV_CODEC_ID_H264: vLocalCodec := avcodec_find_decoder_by_name('h264_cuvid');
AVCodecID.AV_CODEC_ID_HEVC: vLocalCodec := avcodec_find_decoder_by_name('hevc_cuvid');
AVCodecID.AV_CODEC_ID_MJPEG: vLocalCodec := avcodec_find_decoder_by_name('mjpeg_cuvid');
AVCodecID.AV_CODEC_ID_MPEG4: vLocalCodec := avcodec_find_decoder_by_name('mpeg4_cuvid');
else
vLocalCodec := avcodec_find_decoder(fLocalCodecParams.codec_id);
end;
if fLocalCodecParams.codec_type = AVMEDIA_TYPE_VIDEO then
begin
fVideoStreamIndex := vCount;
fCodec := vLocalCodec;
fCodecParams := fLocalCodecParams;
end;
end;
{fCodec.name = h264_cuvid}
fCodecCtx := avcodec_alloc_context3(fCodec);
var vHWDeviceCtx: PAVBufferRef;
try
if av_hwdevice_ctx_create(vHWDeviceCtx, vType, nil, nil, 0) >= 0 then
fCodecCtx.hw_device_ctx := av_buffer_ref(vHWDeviceCtx);
finally
av_buffer_unref(vHWDeviceCtx);
end;
avcodec_open2(fCodecCtx, fCodec, nil);
{
fCodecCtx.codec_id = AV_CODEC_ID_H264
fCodecCtx.pix_fmt = AV_PIX_FMT_MMAL
}
fFrameIn := av_frame_alloc;
fFrameOut := av_frame_alloc;
fFrameOut.format := Integer(AV_PIX_FMT_BGRA);
fFrameOut.width := 640;
fFrameOut.height := 480;
//On getting sws_context I've tried srcFormat = AV_PIX_FMT_MMAL but the result was nil
fScaler := sws_getContext(fCodecCtx.Width, fCodecCtx.Height, AV_PIX_FMT_NV12{fCodecCtx.pix_fmt},
fOutputWidth, fOutputHeight, AV_PIX_FMT_BGRA, SWS_BILINEAR, nil, nil, nil);
fPacket := av_packet_alloc;
while (av_read_frame(fFormatCtx, fPacket) >= 0) do
begin
if fPacket.stream_index = fVideoStreamIndex then
begin
vDecPackResponse := DecodeVideoPacket;
av_packet_unref(fPacket);
if vDecPackResponse < 0 then
Break;
end
end;
Exit(0);
end;
function TDecoder.DecodeVideoPacket: Integer;
var
vResponse: Integer;
vBmp: Vcl.Graphics.TBitmap;
vScaleResult, vSize: Integer;
vBuffer: PByte;
vSWFrame, vTMPFrame: pAVFrame;
begin
Result := 0;
vResponse := avcodec_send_packet(fCodecCtx, fPacket);
if vResponse < 0 then
Exit(vResponse);
while (vResponse >= 0) do
begin
vResponse := avcodec_receive_frame(fCodecCtx, fFrameIn);
if (vResponse = AVERROR_EAGAIN) or (vResponse = AVERROR_EOF) then
Break
else if vResponse < 0 then
Exit(vResponse);
if vResponse >= 0 then
begin
vSWFrame := av_frame_alloc;
if av_hwframe_transfer_data(vSWFrame, fFrameIn, 0) >= 0 then
vTMPFrame := vSWFrame
else
vTMPFrame := fFrameIn;
vSize := av_image_get_buffer_size(AVPixelFormat(vTMPFrame.format), vTMPFrame.width, vTMPFrame.height, 1);
vBuffer := av_malloc(vSize);
if Assigned(vBuffer) then
av_image_copy_to_buffer(vBuffer, vSize, #vTMPFrame.data, #vTMPFrame.linesize, AVPixelFormat(vTMPFrame.format), vTMPFrame.width, vTMPFrame.height, 1);
MoveMemory(vTMPFrame.data[0], vBuffer, vSize);
vTMPFrame.data[0] := vTMPFrame.data[0] + vTMPFrame.linesize[0] * (fCodecCtx.height - 1);
vTMPFrame.linesize[0] := vTMPFrame.linesize[0] * -1;
vTMPFrame.data[1] := vTMPFrame.data[1] + vTMPFrame.linesize[1] * (fCodecCtx.height div 2 - 1);
vTMPFrame.linesize[1] := vTMPFrame.linesize[1] * -1;
vTMPFrame.data[2] := vTMPFrame.data[2] + vTMPFrame.linesize[2] * (fCodecCtx.height div 2 - 1);
vTMPFrame.linesize[2] := vTMPFrame.linesize[2] * -1;
vScaleResult := sws_scale(fScaler, #vTMPFrame.Data, #vTMPFrame.Linesize, 0,
fCodecCtx.Height, #fFrameOut.data, #fFrameOut.Linesize);
if vScaleResult <= 0 then
begin
Break;
end;
vBmp := Vcl.Graphics.TBitmap.Create;
try
vBmp.Height := fOutputHeight;
vBmp.Width := fOutputWidth;
vBmp.PixelFormat := TPixelFormat.pf32bit;
MoveMemory(PByte(vBmp.ScanLine[vBmp.Height -1]),
fFrameOut.data[0], fOutputHeight * fFrameOut.linesize[0]);
//Renders BMP on main thread
// if Assigned(fOnBitmap) then
// fOnBitmap(vBmp);
finally
av_frame_unref(vSWFrame);
av_frame_free(vTMPFrame);
av_freep(#vBuffer);
FreeAndNil(vBmp);
Result := 1;
end;
end;
end;
end;
end.
I've tried using different pixelformats but none of them properly decoded the video.
I use the WinINet library to connect to a website.
Using the Internet Explorer (Win10) it works and shows me the message to select the certificate to use.
This is the delphi code I call:
FUNCTION TRAD.lastOrganization(): Integer;
VAR
js:TlkJSONobject;
ws: TlkJSONstring;
url, resp: String;
count,statusCodeLen, bodyCodeLen: Cardinal;
header,tmp: String;
buffer, body: String;
statusCode: ARRAY [0 .. 1024] OF Char;
bodyCode: ARRAY [0 .. 1024] OF Char;
UrlHandle: HINTERNET;
BEGIN
buffer := '00000000000000000000';
url := contextUrl + '/rest/organization/count';
UrlHandle := InternetOpenUrl(NetHandle, PChar(url), nil, 0, INTERNET_FLAG_RELOAD, 0);
IF NOT ASSIGNED(UrlHandle) THEN
SHOWMESSAGE('Unable to read the amount of Organization using the URL ' + url + ': ' + SysErrorMessage(GetLastError));
statusCodeLen := Length(statusCode);
bodyCodeLen := Length(bodyCode);
count := 0;
IF HttpQueryInfo(UrlHandle, HTTP_QUERY_STATUS_CODE, #statusCode[0], statusCodeLen, count) THEN
BEGIN
buffer := statusCode;
IF buffer <> '200' THEN
BEGIN
ShowMessage('While read amount of Organization I got a status code ' + buffer + ' but 200 was expected.');
EXIT;
END;
END;
count := 0;
body := '';
REPEAT
FillChar(bodyCode, bodyCodeLen, 0);
IF NOT InternetReadFile(UrlHandle, #bodyCode[0], bodyCodeLen, count) THEN
BEGIN
ShowMessage('Problem on reading from response stream while read the amount of Organization using the URL ' + url + '.');
EXIT;
END;
IF count > 0 THEN
BEGIN
tmp := bodyCode;
body := body + LeftStr(tmp, count);
END;
UNTIL count = 0;
InternetCloseHandle(UrlHandle);
Result := strtoint(body);
END;
If I call the method, I get this message:
Buuut, using the Edge-Browser I have to specify a certificate, and it works just great.
Question
How to specify the certificate?
Edit (new informations):
If I change the code to
FUNCTION TRAD.lastOrganization(): Integer;
VAR
js:TlkJSONobject;
ws: TlkJSONstring;
url, resp: String;
count,statusCodeLen, bodyCodeLen: Cardinal;
header,tmp: String;
buffer, body: String;
statusCode: ARRAY [0 .. 1024] OF Char;
bodyCode: ARRAY [0 .. 1024] OF Char;
UrlHandle: HINTERNET;
BEGIN
buffer := '00000000000000000000';
url := contextUrl + '/rest/organization/count';
UrlHandle := InternetOpenUrl(NetHandle, PChar(url), nil, 0, INTERNET_FLAG_RELOAD, 0);
IF NOT ASSIGNED(UrlHandle) THEN
raiseLastOSError();
It shows:
Consider the use of InternetErrorDlg
Code example:
function WebSiteConnect(const UserAgent: string; const Server: string; const Resource: string;): string;
var
hInet: HINTERNET;
hConn: HINTERNET;
hReq: HINTERNET;
dwLastError:DWORD;
nilptr:Pointer;
dwRetVal:DWORD;
bLoop: boolean;
port:Integer;
begin
hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if hInet = nil then exit;
hConn := InternetConnect(hInet, PChar(Server), INTERNET_DEFAULT_HTTPS_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);
if hConn = nil then
begin
InternetCloseHandle(hInet);
exit;
end;
hReq := HttpOpenRequest(hConn, 'GET', PChar(Resource), 'HTTP/1.0', nil, nil, INTERNET_FLAG_SECURE, 0);
if hReq = nil then
Begin
InternetCloseHandle(hConn);
InternetCloseHandle(hInet);
exit;
end;
bLoop := true;
while bLoop do
begin
if HttpSendRequest(hReq, nil, 0, nil, 0) then
dwLastError := ERROR_SUCCESS
else
dwLastError:= GetLastError();
if dwLastError = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED then
begin
dwRetVal:= InternetErrorDlg(application.handle, hReq, dwLastError,
FLAGS_ERROR_UI_FILTER_FOR_ERRORS or
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA or
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS,
nilptr );
if dwRetVal = ERROR_INTERNET_FORCE_RETRY then
continue
else // CANCEL button
begin
InternetCloseHandle(hReq);
InternetCloseHandle(hConn);
InternetCloseHandle(hInet);
exit;
end;
end
else
bLoop := false;
end;
Result:= ...
end;
Using WinHTTP (You can do the same with WinInetHTTP) you can set the certificate like this via ActiveX :
// Instantiate a WinHttpRequest object.
var HttpReq = new ActiveXObject("WinHttp.WinHttpRequest.5.1");
// Open an HTTP connection.
HttpReq.Open("GET", "https://www.fabrikam.com/", false);
// Select a client certificate.
HttpReq.SetClientCertificate(
"LOCAL_MACHINE\\Personal\\My Middle-Tier Certificate");
// Send the HTTP Request.
HttpReq.Send();
So that easy with ActiveX but it's not really what you want (i gave you the example as illustration). So with the windows API, WinHTTP enables you to select and send a certificate from a local certificate store. The following code example shows how to open a certificate store and locate a certificate based on subject name after the ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED error has been returned.
if( !WinHttpReceiveResponse( hRequest, NULL ) )
{
if( GetLastError( ) == ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED )
{
//MY is the store the certificate is in.
hMyStore = CertOpenSystemStore( 0, TEXT("MY") );
if( hMyStore )
{
pCertContext = CertFindCertificateInStore( hMyStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0,
CERT_FIND_SUBJECT_STR,
(LPVOID) szCertName, //Subject string in the certificate.
NULL );
if( pCertContext )
{
WinHttpSetOption( hRequest,
WINHTTP_OPTION_CLIENT_CERT_CONTEXT,
(LPVOID) pCertContext,
sizeof(CERT_CONTEXT) );
CertFreeCertificateContext( pCertContext );
}
CertCloseStore( hMyStore, 0 );
// NOTE: Application should now resend the request.
}
}
}
I have a problem with MapiSendMail function of MAPI32.dll. Everything seems fine, message is completed, then I send it by winapi function, and i get an Access violation error, it happend in MAPISendMail. Here's the fragment of the code:
MAPIModule := LoadLibrary(PWideChar(MAPIDLL));
if MAPIModule = 0 then
Result := -1
else
try
#SM := GetProcAddress(MAPIModule, 'MAPISendMail');
if #SM <> nil then
begin
Result := SM(0, application.Handle, Msg, MAPI_DIALOG {or MAPI_LOGON_UI}, 0);
end
else
Result := 1;
finally
end;
Also I was trying to change GetProcAddres to MAPISendMailW or MAPISendMailHelper, but then #SM was nil.
#Edit1
function TMail._SendMAPIEmail(const aTo, aAtts: array of AnsiString; const body, subject, SenderName, SenderEmail: string; ShowError: Boolean = true): Integer;
var
SM: TFNMapiSendMail;
Msg: MapiMessage;
lpSender: MapiRecipDesc;
Recips: array of MapiRecipDesc;
Att: array of MapiFileDesc;
TempAttNames: array of pAnsiChar;
TempAttNamesAnsi: array of AnsiString;
TempAttPaths: array of pAnsiChar;
TempRecip: array of pAnsiChar;
p1, LenTo, LenAtts: Integer;
MAPIModule: HModule;
sError: String;
i: integer;
begin
try
FillChar(Msg, SizeOf(Msg), 0);
{ get the length of all arrays passed to this function }
LenTo := length(aTo);
if Trim(aAtts[0]) <> '' then
LenAtts := length(aAtts)
else
LenAtts := 0;
{ ... }
SetLength(Recips, LenTo);
SetLength(TempRecip, LenTo);
Setlength(Att, LenAtts);
SetLength(TempAttNames, LenAtts);
SetLength(TempAttPaths, LenAtts);
SetLength(TempAttNamesAnsi, LenAtts);
{ to }
for p1 := 0 to LenTo - 1 do
begin
FillChar(Recips[p1], SizeOf(Recips[p1]), 0);
Recips[p1].ulReserved := 0;
Recips[p1].ulRecipClass := MAPI_TO;
{ Upgrade }
Recips[p1].lpszName := '';
TempRecip[p1] := pAnsichar(aTo[p1]);
Recips[p1].lpszAddress := TempRecip[p1];
end;
{ atts }
for p1 := 0 to LenAtts - 1 do
begin
FillChar(Att[p1], SizeOf(Att[p1]), 0);
FillChar(TempAttPaths[p1], SizeOf(pAnsiChar), 0);
FillChar(TempAttNames[p1], SizeOf(pAnsiChar), 0);
FillChar(TempAttNamesAnsi[01], SizeOf(AnsiChar), 0);
Att[p1].ulReserved := 0;
Att[p1].flFlags := 0;
Att[p1].nPosition := Cardinal($FFFFFFFF);
{ Upgrade }
TempAttPaths[p1] := pAnsichar(aAtts[p1]);
Att[p1].lpszPathName := TempAttPaths[p1];
TempAttNamesAnsi[p1] := AnsiString((ExtractFileName(string(aAtts[p1]))));
TempAttNames[p1] := pAnsiChar(TempAttNamesAnsi[p1]);
Att[p1].lpszFileName := TempAttNames[p1];
end;
{ fill the message }
with Msg do
begin
ulReserved := 0;
if subject <> '' then
{ Upgrade }
lpszSubject := pAnsichar(AnsiString(subject));
if body <> '' then
{ Upgrade }
lpszNoteText := pAnsichar(AnsiString(body));
if SenderEmail <> '' then
begin
lpSender.ulRecipClass := MAPI_ORIG;
if SenderName = '' then
lpSender.lpszName := pAnsichar(AnsiString(SenderEmail))
else
lpSender.lpszName := pAnsichar(AnsiString(SenderName));
lpSender.lpszAddress := pAnsichar(AnsiString(SenderEmail));
lpSender.ulEIDSize := 0;
lpSender.lpEntryID := nil;
lpOriginator := #lpSender;
end
else
Msg.lpOriginator := nil;
Msg.lpszMessageType := nil;
Msg.lpszDateReceived := nil;
Msg.lpszConversationID := nil;
Msg.flFlags := 0;
Msg.nRecipCount := LenTo;
Msg.lpRecips := #Recips[0];
Msg.nFileCount := LenAtts;
Msg.lpFiles := #Att[0];
end;
MAPIModule := LoadLibrary(PWideChar(MAPIDLL));
if MAPIModule = 0 then
Result := -1
else
try
#SM := GetProcAddress(MAPIModule, 'MAPISendMail');
if #SM <> nil then
begin
//Result := MapiSendMail(0, application.Handle, Msg, MAPI_DIALOG, 0);
Result := SM(0, 0, Msg, MAPI_DIALOG {or MAPI_LOGON_UI}, 0);
end
else
Result := 1;
finally
if Assigned(Att) and (Msg.nFileCount > 0) then
begin
for i := 0 to Msg.nFileCount - 1 do
begin
if Assigned(Att[i].lpszPathName) then
Att[i].lpszPathName := nil;
if Assigned(Att[i].lpszFileName) then
Att[i].lpszFileName := nil;
//FreeMem(Att[i].lpszPathName);
//Dispose(Att[i].lpszPathname);
//StrDispose(Att[i].lpszPathName);
//Dispose(Att[i].lpszFileName);
//StrDispose(Att[i].lpszFileName);
end;
Att := nil;
end;
if Assigned(Recips) and (Msg.nRecipCount > 0) then
begin
for i := 0 to Msg.nRecipCount - 1 do
begin
if Assigned(Recips[i].lpszName) then
Recips[i].lpszName := nil;
if Assigned(Recips[i].lpszAddress) then
Recips[i].lpszAddress := nil;
//if Assigned(Recips[i].lpszName) then
//Dispose(Recips[i].lpszName);
//if Assigned(Recips[i].lpszAddress) then
//Dispose(Recips[i].lpszAddress);
end;
Recips := nil;
end;
end;
Under Win32
Under Win32 it should not be a problem. Just first try calling MapiSendMail with very simple MapiMessage and if it will work, add complexity little by little. Your code is just too complex to debug it visually. Did you call MapiSendMail with very simple MapiMessage, just for testing? Please try the following code, it works for sure:
procedure TestSendExA(const APath1, ACaption1, APath2, ACaption2: AnsiString);
var
R: Integer;
MSG: TMapiMessage;
F: Array [0..1] of TMapiFileDesc;
Recipients: array[0..1] of TMapiRecipDesc;
Originator : array[0..0] of TMapiRecipDesc;
begin
if not FileExists(APath1) or not FileExists(APath2) then raise Exception.Create('File not found');
FillChar(Msg, SizeOf(Msg), 0);
Msg.lpszSubject := 'testo';
Msg.lpszNoteText := 'Hi there!';
Msg.lpszDateReceived := '2015/01/25 12:34';
Msg.lpszConversationId := '1234.test#ritlabs.com';
Msg.flFlags := MAPI_RECEIPT_REQUESTED;
FillChar(Recipients, SizeOf(Recipients), 0);
with Recipients[0] do
begin
ulRecipClass := MAPI_TO;
lpszName := 'Maxim Masiutin';
lpszAddress := 'maxim.test#ritlabs.com';
end;
with Recipients[1] do
begin
ulRecipClass := MAPI_CC;
lpszName := 'Vasilii Pupkin';
lpszAddress := 'pupkin.test#ritlabs.com';
end;
FillChar(Originator, SizeOf(Originator), 0);
with Originator[0] do
begin
ulRecipClass := MAPI_TO;
lpszName := 'Maxim Masiutin';
lpszAddress := 'max#ritlabs.com';
end;
Msg.lpOriginator := #Originator;
Msg.nRecipCount := 2;
Msg.lpRecips := #Recipients;
Msg.nFileCount := 2;
Msg.lpFiles := #F;
FillChar(F, SizeOf(F), 0);
F[0].lpszPathName := PAnsiChar(APath1);
F[0].lpszFileName := PAnsiChar(ACaption1);
F[1].lpszPathName := PAnsiChar(APath2);
F[1].lpszFileName := PAnsiChar(ACaption2);
R := MAPISendMail(MapiSession, 0, Msg, 0, 0);
end;
The MapiSession in the above example is a handle to the session returned by MapiLogon.
This sample code requires that you pass two valid file paths to valid files in APath1 and APath2.
Under Win64
It is the record alignment of MapiMessage and other records that it is important when you work with Simple MAPI from Delphi: (1) make sure the records don't have "packed" prefix; and (2) make sure you have {$A8} compiler directive is explicitly specified before first record definition. This will work fine under both Win32 and Win64.
I have following code:
if (APartitionStyle = 0) then //mbr
begin
hDevice := CreateFile(
PChar(ADisk),
GENERIC_WRITE and GENERIC_READ,
FILE_SHARE_WRITE and FILE_SHARE_READ,
nil,
OPEN_EXISTING,
0,
0);
error := SysErrorMessage(GetLastError);
if (hDevice = INVALID_HANDLE_VALUE) then
begin
error := SysErrorMessage(GetLastError);
result := error;
end;
dwIoControlCode := IOCTL_DISK_CREATE_DISK;
dsk.PartitionStyle := PARTITION_STYLE_MBR;
dsk.mbr.Signature := Random(9999);
lpInBuffer := #dsk;
nInBufferSize := sizeof(CREATE_DISK);
lpOutBuffer := nil;
nOutBufferSize := 0;
lpOverlapped := nil;
bresult := DeviceIOControl(
hDevice,
dwIoControlCode,
lpInBuffer,
nInBufferSize,
lpOutBuffer,
nOutBufferSize,
lpBytesReturned,
lpOverlapped);
if not bresult then
begin
error := SysErrorMessage(GetLastError);
result := error;
end;
I have executed the code as administrator or system and as user (with admin privilegs).
I have read something like: Driver is locked. Is there something missing in the code?
The handle is successfully created. On DeviceIOControl I get an error "Access Denied".
You are passing incorrect values to CreateFile(). You are using the and operator to combine bit flags:
hDevice := CreateFile(
PChar(ADisk),
GENERIC_WRITE and GENERIC_READ, { = 0 ! }
FILE_SHARE_WRITE and FILE_SHARE_READ, { = 0 ! }
nil,
OPEN_EXISTING,
0,
0);
You need to use the or operator instead:
hDevice := CreateFile(
PChar(ADisk),
GENERIC_WRITE or GENERIC_READ, { = $C0000000 ! }
FILE_SHARE_WRITE or FILE_SHARE_READ, { = $00000003 ! }
nil,
OPEN_EXISTING,
0,
0);
In theory connection attempt should terminate after 5 seconds. However in practice I still get infinite timeout. Is there any way to terminate connection from outside. For example I could use timer and then execute proper function to abort. Another nasty workaround would be fire thread and kill it with TerminateThread function.
function DownloadFile(URL, {User, Pass,} FileName: string): Boolean;
const
BufferSize = 1024;
var
hSession, hURL: HInternet;
Buffer: array[1..BufferSize] of Byte;
BufferLen,Connect_timeout: DWORD;
F: File;
User,Pass:string;
begin
User:='';
Pass:='';
Result := False;
hSession := InternetOpen('', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0) ;
Connect_timeout := 5000 ;
InternetSetOption(hSession, INTERNET_OPTION_CONNECT_TIMEOUT, Pointer(#Connect_timeout), sizeof(Connect_timeout));
// Establish the secure connection
InternetConnect (
hSession,
PChar(URL),
INTERNET_DEFAULT_HTTPS_PORT,
PChar(User),
PChar(Pass),
INTERNET_SERVICE_HTTP,
0,
0
);
try
hURL := InternetOpenURL(hSession, PChar(URL), nil, 0, 0, 0) ;
try
AssignFile(f, FileName);
Rewrite(f,1);
try
repeat
InternetReadFile(hURL, #Buffer, SizeOf(Buffer), BufferLen) ;
BlockWrite(f, Buffer, BufferLen)
until BufferLen = 0;
finally
CloseFile(f) ;
Result := True;
end;
finally
InternetCloseHandle(hURL)
end
finally
InternetCloseHandle(hSession)
end;
end;