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.
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 have an app with a TListView and I want to populate data from JSON inside its Items by using TJSONIterator.Next(). The code I use displays the results I want, except for the first one.
How can I parse these JSON objects correctly, what am I doing wrong?
Data: Data.json
{
"event":"subscribe-status",
"status":"ok",
"success":[
{
"symbol":"EUR/USD",
"exchange":"PHYSICAL CURRENCY",
"mic_code":"PHYSICAL CURRENCY",
"country":"",
"type":"Physical Currency"
},
{
"symbol":"USD/JPY",
"exchange":"PHYSICAL CURRENCY",
"mic_code":"PHYSICAL CURRENCY",
"country":"",
"type":"Physical Currency"
},
{
"symbol":"BTC/USD",
"exchange":"Coinbase Pro",
"mic_code":"Coinbase Pro",
"country":"",
"type":"Digital Currency"
},
{
"symbol":"ETH/BTC",
"exchange":"Huobi",
"mic_code":"Huobi",
"country":"",
"type":"Digital Currency"
}
],
"fails":null
}
Code app:
LStringReader := TStreamReader.Create('../../Data.json', TEncoding.UTF8, True);
LJsonTextReader := TJsonTextReader.Create(LStringReader);
LIterator := TJSONIterator.Create(LJsonTextReader);
NObjJSON := LIterator.AsInteger;
ListView1.Items.Clear;
ListView1.BeginUpdate;
try
while True do
begin
while LIterator.Next do
begin
if LIterator.&Type in [TJsonToken.StartObject, TJsonToken.StartArray] then
begin
LIterator.Recurse;
LIterator.Next;
oItem := ListView1.Items.Add;
for NObjJSON := 0 to ListView1.ItemCount -1 do
begin
oItem.Text := 'Object #' + NObjJSON.ToString + ' ' + LIterator.AsValue.ToString;
oItem.Detail := 'Key:' +LIterator.Key;
end
end;
end;
if LIterator.InRecurse then
LIterator.Return
else
Break;
end;
finally
ListView1.EndUpdate;
LIterator.Free;
LJsonTextReader.Free;
lStringReader.Free;
Memo1.Lines.Text := NObjJSON.ToString;
end;
Add this recurse / next at beginning of your loop to prepare to enter array :
while LIterator.Next do
begin
if LIterator.&Type = TJsonToken.StartArray then
begin
LIterator.Recurse;
LIterator.Next;
end;
You can check this exemple in the doc : https://docwiki.embarcadero.com/CodeExamples/Sydney/en/RTL.JSONIterator
The code below is easier to read :
procedure TFormX.LoadJSON;
const
cValue = 'symbol';
var
LValue: TJSONValue;
LArray: TJSONArray;
i: integer;
oItem: TListViewItem;
begin
LValue := TJSONObject.ParseJSONValue('{json}');
LArray := LValue.FindValue('success') as TJSONArray;
if Assigned(LArray) then
begin
for i := 0 to LArray.Count - 1 do
begin
oItem := ListView1.Items.Add;
oItem.Text := 'Object #' + i.ToString + ' ' + LArray.Items[i].GetValue<string>(cValue);
oItem.Detail := 'Key:' + cValue;
end;
end;
end;
After all, i found the correct solution:*
var
LIterator: TJSONIterator;
LJsonTextReader: TJsonTextReader;
LStringReader: TStreamReader;
NObjJSON: Integer;
begin
LStringReader := TStreamReader.Create('../../Data.json', TEncoding.UTF8, True);
LJsonTextReader := TJsonTextReader.Create(LStringReader);
LIterator := TJSONIterator.Create(LJsonTextReader);
NObjJSON := LIterator.AsInteger;
ListView1.Items.Clear;
ListView1.BeginUpdate;
try
while True do
begin
while LIterator.Next do
begin
if LIterator.&Type in [TJsonToken.StartObject, TJsonToken.StartArray] then
begin
Memo1.Lines.Add(LIterator.Key);
LIterator.Recurse;
end
else if LIterator.Path = 'success['+NObjJSON.ToString+'].symbol' then
begin
Memo1.Lines.Add(LIterator.AsValue.ToString);
oItem := ListView1.Items.Add;
for NObjJSON := 0 to ListView1.ItemCount -1 do
oItem.Text := 'Object #' + NObjJSON.ToString + ' ' + LIterator.AsValue.ToString;
end
end;
if LIterator.InRecurse then
LIterator.Return
else
Break;
end;
finally
ListView1.EndUpdate;
LIterator.Free;
LJsonTextReader.Free;
LStringReader.Free;
end;
end;
NObjJSON is used to count the number of objects inside array and it returns 4.
You can use a simple integer (I) and replace "for NObjJSON := 0 to ListView1.ItemCount -1 do" by for I := 0 to ListView1.ItemCount -1 do but the number of objects will return 0.
I'm trying to get stream video from USB Web-camera in Delphi XE. Found a working example, but I can't figure out how to get all supported video formats (resolution, color depth, etc). This example works well with fixed Mediatype:
var
Form1: TForm1;
IniFile: TIniFile;
DeviceName: OleVariant;
PropertyName: IPropertyBag;
pDevEnum: ICreateDEvEnum;
pEnum: IEnumMoniker;
pMoniker: IMoniker;
MArray1: array of IMoniker;
FGraphBuilder: IGraphBuilder;
FCaptureGraphBuilder: ICaptureGraphBuilder2;
FMux: IBaseFilter;
FSink: IFileSinkFilter;
FMediaControl: IMediaControl;
FVideoWindow: IVideoWindow;
FVideoCaptureFilter: IBaseFilter;
FAudioCaptureFilter: IBaseFilter;
FVideoRect: TRect;
FBaseFilter: IBaseFilter;
FSampleGrabber: ISampleGrabber;
MediaType: AM_MEDIA_TYPE;
function TForm1.Initializ: HResult;
begin
Result := CoCreateInstance(CLSID_SystemDeviceEnum, NIL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, pDevEnum);
if Result <> S_OK then
EXIT;
Result := pDevEnum.CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
pEnum, 0);
if Result <> S_OK then
EXIT;
setlength(MArray1, 0);
while (S_OK = pEnum.Next(1, pMoniker, Nil)) do
begin
setlength(MArray1, length(MArray1) + 1);
MArray1[length(MArray1) - 1] := pMoniker;
Result := pMoniker.BindToStorage(NIL, NIL, IPropertyBag, PropertyName);
if FAILED(Result) then
Continue;
Result := PropertyName.Read('FriendlyName', DeviceName, NIL);
if FAILED(Result) then
Continue;
ListBox1.Items.Add(DeviceName);
end;
if ListBox1.Count = 0 then
begin
ShowMessage('Webcam not found!');
Result := E_FAIL;
EXIT;
end;
ListBox1.ItemIndex := 0;
Result := S_OK;
end;
function TForm1.CreateGraph: HResult;
var
pConfigMux: IConfigAviMux;
begin
FVideoCaptureFilter := NIL;
FVideoWindow := NIL;
FMediaControl := NIL;
FSampleGrabber := NIL;
FBaseFilter := NIL;
FCaptureGraphBuilder := NIL;
FGraphBuilder := NIL;
Result := CoCreateInstance(CLSID_FilterGraph, NIL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, FGraphBuilder);
if FAILED(Result) then
EXIT;
Result := CoCreateInstance(CLSID_SampleGrabber, NIL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, FBaseFilter);
if FAILED(Result) then
EXIT;
Result := CoCreateInstance(CLSID_CaptureGraphBuilder2, NIL,
CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, FCaptureGraphBuilder);
if FAILED(Result) then
EXIT;
Result := FGraphBuilder.AddFilter(FBaseFilter, 'GRABBER');
if FAILED(Result) then
EXIT;
Result := FBaseFilter.QueryInterface(IID_ISampleGrabber, FSampleGrabber);
if FAILED(Result) then
EXIT;
if FSampleGrabber <> NIL then
begin
ZeroMemory(#MediaType, sizeof(AM_MEDIA_TYPE));
with MediaType do
begin
majortype := MEDIATYPE_Video;
subtype := MEDIASUBTYPE_RGB24;
formattype := FORMAT_VideoInfo;
end;
FSampleGrabber.SetMediaType(MediaType);
FSampleGrabber.SetBufferSamples(TRUE);
FSampleGrabber.SetOneShot(FALSE);
end;
Result := FCaptureGraphBuilder.SetFiltergraph(FGraphBuilder);
if FAILED(Result) then
EXIT;
if ListBox1.ItemIndex >= 0 then
begin
MArray1[ListBox1.ItemIndex].BindToObject(NIL, NIL, IID_IBaseFilter,
FVideoCaptureFilter);
FGraphBuilder.AddFilter(FVideoCaptureFilter, 'VideoCaptureFilter');
end;
Result := FCaptureGraphBuilder.RenderStream(#PIN_CATEGORY_PREVIEW, nil,
FVideoCaptureFilter, FBaseFilter, nil);
if FAILED(Result) then
EXIT;
Result := FGraphBuilder.QueryInterface(IID_IVideoWindow, FVideoWindow);
if FAILED(Result) then
EXIT;
FVideoWindow.put_WindowStyle(WS_CHILD or WS_CLIPSIBLINGS);
FVideoWindow.put_Owner(Panel1.Handle);
FVideoRect := Panel1.ClientRect;
FVideoWindow.SetWindowPosition(FVideoRect.Left, FVideoRect.Top,
FVideoRect.Right - FVideoRect.Left, FVideoRect.Bottom - FVideoRect.Top);
FVideoWindow.put_Visible(TRUE);
Result := FGraphBuilder.QueryInterface(IID_IMediaControl, FMediaControl);
if FAILED(Result) then
EXIT;
FMediaControl.Run();
end;
How can I get all webcam supported video formats to combobox? If I need something to add, please, post in comment, thanks.
The code snippet provided is not quite relevant and presumably is just what you have at the moment. To enumerate video formats you typically obtain an output pin of interest first, which you don't do in your code snippet and rely on RenderStream call to do dirty work for you.
Then, you obtain IAMStreamConfig interface pointer from the pin and enumerate the media types (formats). Alternatively you can enumerate using IPin::EnumMediaTypes, however IAMStreamConfig::GetStreamCaps is the canonical way, esp. for webcams.
Bonus code here:
// The TVideoSample class provides access to WebCams and similar Video-capture
// devices via DirectShow.
...
// Fills "FormatArr" with list of all supported video formats (resolution, compression etc...)
FUNCTION TVideoSample.LoadListOfResolution: HResult;
...
I use the OnCustomDrawItem event to draw a TTreeView like this :
Here is my code :
procedure Tform1.trvArbreCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
var
vRect : TRect;
vBmp : TBitmap;
vBmpRect : TRect;
vTreeView : TTreeView;
vBarreInfo : TScrollInfo;
vDeltaX : Integer;
begin
DefaultDraw := False;
vTreeView := TTreeView(Sender);
vRect := Node.DisplayRect(False);
vBmp := TBitmap.Create();
FillChar(vBarreInfo, SizeOF(vBarreInfo), 0);
vBarreInfo.cbSize := SizeOf(vBarreInfo);
vBarreInfo.fMask := SIF_RANGE or SIF_POS;
if GetScrollInfo(trvArbre.Handle, SB_HORZ, vBarreInfo) then
begin
if vBarreInfo.nMax > vRect.Right - vRect.Left then
begin
vBmp.Width := vBarreInfo.nMax + 1;
vBmp.Height := vRect.Bottom - vRect.Top;
vDeltaX := vBarreInfo.nPos;
end
else
begin
vBmp.Width := vRect.Right - vRect.Left;
vBmp.Height := vRect.Bottom - vRect.Top;
vDeltaX := 0;
end;
end
else
begin
vBmp.Width := vRect.Right - vRect.Left;
vBmp.Height := vRect.Bottom - vRect.Top;
vDeltaX := 0;
end;
vBmpRect := Rect(0, 0, vBmp.Width, vBmp.Height);
if cdsSelected in State then
begin
vBmp.Canvas.Brush.Color := cMenuDownFond;
vBmp.Canvas.Pen .Color := cMenuDownBordure;
end
else if cdsHot in State then
begin
vBmp.Canvas.Brush.Color := cMenuSurvolFond;
vBmp.Canvas.Pen .Color := cMenuSurvolBordure;
end
else
begin
vBmp.Canvas.Brush.Color := clWhite;
vBmp.Canvas.Pen .Color := clwhite;
end;
vBmp.Canvas.Rectangle(vBmpRect);
vBmpRect.Left := vBmpRect.Left + 3;
vBmpRect.Left := vBmpRect.Left + (Node.Level * vTreeView.Indent);
if Node.StateIndex >= 0 then
begin
vTreeView.StateImages.Draw(vBmp.Canvas, vBmpRect.Left, vBmpRect.Top, Node.StateIndex);
end;
vBmpRect.Left := vBmpRect.Left + 18;
vTreeView.Images.Draw(vBmp.Canvas, vBmpRect.Left, vBmpRect.Top, Node.ImageIndex);
vBmpRect.Left := vBmpRect.Left + 18 + 3;
vBmp.Canvas.Font := vTreeView.Font;
DrawText
(
vBmp.Canvas.Handle,
PChar(Node.Text),
Length(Node.Text),
vBmpRect,
DT_SINGLELINE or DT_LEFT or DT_VCENTER or DT_NOPREFIX or DT_END_ELLIPSIS
);
BitBlt
(
Sender.Canvas.Handle,
vRect.Left,
vRect.Top,
vRect.Right - vRect.Left,
vRect.Bottom - vRect.Top,
vBmp.Canvas.Handle,
vDeltaX,
0,
SRCCOPY
);
FreeAndNil(vBmp);
end;
My problem is that the node "My last node wich is not too long" is not too long to justify the presence of the horizontal scrollbar.
When I set DefaultDraw to true I obtain :
It seems that the width of the node is computed with a font I don't use.
I tried to change the font of the canvas, to use Windows API, to use the OnAdvancedCustomDrawItem with no result.
Thanks.
I use Delphi 7. I copied ComCtrls.pas in the folder of my application. I changed procedure TCustomTreeView.CNNotify(var Message: TWMNotify);. Line 8979 from Result := Result or CDRF_SKIPDEFAULT to Result := Result or CDRF_SKIPDEFAULT; and I commented line 8980 else if FCanvasChanged then in order to simulate DefaultDraw=True and FCanvasChanged even if I set DefaultDraw to False in event et don't change font. After a lot of tests, I don't see any caveats.
I got the following code from a newsgroup posting. Strangely, it isn't working for me in Delphi 2010; An exception is being thrown at the LsaOpenPolicy function call:
function AddLogonAsAService(ID: pchar): boolean;
const
Right: PChar = 'SeServiceLogonRight';
var
FResult: NTSTATUS;
//szSystemName: LPTSTR;
FObjectAttributes: TLSAObjectAttributes;
FPolicyHandle: LSA_HANDLE;
Server, Privilege: TLSAUnicodeString;
FSID: PSID;
cbSid: DWORD;
ReferencedDomain: LPTSTR;
cchReferencedDomain: DWORD;
peUse: SID_NAME_USE;
PrivilegeString: String;
begin
Result := false;
try
ZeroMemory(#FObjectAttributes, sizeof(FObjectAttributes));
Server.Buffer := nil;
Server.Length := 0;
Server.MaximumLength := 256;
PrivilegeString := Right; //or some other privilege
Privilege.Buffer := PChar(PrivilegeString);
Privilege.Length := 38;
Privilege.MaximumLength := 256;
FResult := LsaOpenPolicy(
#Server, //this machine, because the Buffer is NIL
#FObjectAttributes,
POLICY_ALL_ACCESS,
FPolicyHandle);
if FResult = STATUS_SUCCESS then begin
cbSid := 128;
cchReferencedDomain := 16;
GetMem(FSID, cbSid);
//FSID:=PSID(HeapAlloc(GetProcessHeap(), 0, cbSid));
GetMem(ReferencedDomain, cchReferencedDomain);
//ReferencedDomain := LPTSTR(HeapAlloc(GetProcessHeap(), 0, cchReferencedDomain * sizeof(ReferencedDomain^)));
if LookupAccountName(nil, ID, FSID, cbSid, ReferencedDomain,
cchReferencedDomain, peUse) then begin
FResult := LsaAddAccountRights(FPolicyHandle, FSID, #Privilege, 1);
Result := FResult = STATUS_SUCCESS;
end;
FreeMem(FSID, cbSid);
FreeMem(ReferencedDomain, cchReferencedDomain);
end;
except
Result := false;
end;
end;
Original posting may be found at Google Groups archive:
From: "andrew"
Newsgroups:
borland.public.delphi.winapi
Subject: NetUserAdd and assigning user
rights
Date: Tue, 25 Sep 2001 10:08:35 +1000
Thanks in advance for any answers.
According to the MSDN docs you should not use an LSA_UNICODE_STRING with the Buffer set to nil but pass nil instead: LsaOpenPolicy(nil, ...
/EDIT:
The code below works fine for me using Jedi Apilib so I think something might be wrong with your definition (maybe calling convention?), so please add this to your code.
Also you are specifying maximum buffer size of 256 in the LSA_UNICODE_STRING's which is incorrect, in the first case the maximum buffer is 0.
uses
JwaWinType, JwaNtSecApi;
procedure TForm1.Button1Click(Sender: TObject);
var
ObjectAttribs: LSA_OBJECT_ATTRIBUTES;
PolicyHandle: LSA_HANDLE;
nts: NTSTATUS;
begin
ZeroMemory(#ObjectAttribs, SizeOf(ObjectAttribs));
nts := LsaOpenPolicy(nil, ObjectAttribs, POLICY_ALL_ACCESS, PolicyHandle);
Memo1.Lines.Add(Format('nts=%.8x', [nts]));
end;
Fixed/changed function, tested on Win7 under D2009 (but should work on older/newer too). Of course app. must be running with admin rights.
uses
JwaWinNT, JwaWinType, JwaNtStatus, JwaNtSecApi, JwaLmCons;
function AddPrivilegeToAccount(AAccountName, APrivilege: String): DWORD;
var
lStatus: TNTStatus;
lObjectAttributes: TLsaObjectAttributes;
lPolicyHandle: TLsaHandle;
lPrivilege: TLsaUnicodeString;
lSid: PSID;
lSidLen: DWORD;
lTmpDomain: String;
lTmpDomainLen: DWORD;
lTmpSidNameUse: TSidNameUse;
{$IFDEF UNICODE}
lPrivilegeWStr: String;
{$ELSE}
lPrivilegeWStr: WideString;
{$ENDIF}
begin
ZeroMemory(#lObjectAttributes, SizeOf(lObjectAttributes));
lStatus := LsaOpenPolicy(nil, lObjectAttributes, POLICY_LOOKUP_NAMES, lPolicyHandle);
if lStatus <> STATUS_SUCCESS then
begin
Result := LsaNtStatusToWinError(lStatus);
Exit;
end;
try
lTmpDomainLen := JwaLmCons.DNLEN; // In 'clear code' this should be get by LookupAccountName
SetLength(lTmpDomain, lTmpDomainLen);
lSidLen := SECURITY_MAX_SID_SIZE;
GetMem(lSid, lSidLen);
try
if LookupAccountName(nil, PChar(AAccountName), lSid, lSidLen, PChar(lTmpDomain),
lTmpDomainLen, lTmpSidNameUse) then
begin
lPrivilegeWStr := APrivilege;
lPrivilege.Buffer := PWideChar(lPrivilegeWStr);
lPrivilege.Length := Length(lPrivilegeWStr) * SizeOf(Char);
lPrivilege.MaximumLength := lPrivilege.Length;
lStatus := LsaAddAccountRights(lPolicyHandle, lSid, #lPrivilege, 1);
Result := LsaNtStatusToWinError(lStatus);
end else
Result := GetLastError;
finally
FreeMem(lSid);
end;
finally
LsaClose(lPolicyHandle);
end;
end;
procedure TForm2.Button1Click(Sender: TObject);
var
lStatus: DWORD;
begin
lStatus := AddPrivilegeToAccount('Administrators'{or any account/group name}, 'SeServiceLogonRight');
if lStatus = ERROR_SUCCESS then
Caption := 'OK'
else
Caption := SysErrorMessage(lStatus);
end;