I'm testing this code Windows 7 32 and 64 bit, but still, it does not work the glass effect in any case, not return any errors, just does not work me.
program test;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,System.SysUtils,DH_Form_Effects;
type
DWM_BLURBEHIND = record
dwFlags : DWORD;
fEnable : BOOL;
hRgnBlur : HRGN;
fTransitionOnMaximized : BOOL;
end;
function DwmEnableBlurBehindWindow(hWnd : HWND; const pBlurBehind : DWM_BLURBEHIND) : HRESULT; stdcall; external 'dwmapi.dll' name 'DwmEnableBlurBehindWindow';//function to enable the glass effect
function GetConsoleWindow: HWND; stdcall; external kernel32 name 'GetConsoleWindow'; //get the handle of the console window
function DWM_EnableBlurBehind(hwnd : HWND; AEnable: Boolean; hRgnBlur : HRGN = 0; ATransitionOnMaximized: Boolean = False; AFlags: Cardinal = 1): HRESULT;
var
pBlurBehind : DWM_BLURBEHIND;
begin
pBlurBehind.dwFlags:=AFlags;
pBlurBehind.fEnable:=AEnable;
pBlurBehind.hRgnBlur:=hRgnBlur;
pBlurBehind.fTransitionOnMaximized:=ATransitionOnMaximized;
Result:=DwmEnableBlurBehindWindow(hwnd, pBlurBehind);
end;
begin
try
DWM_EnableBlurBehind(GetConsoleWindow(), True);
Writeln('See my glass effect');
Writeln('Go Delphi Go');
Readln;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.
Does this have any requirement to run? What is the problem ?
It works for me (on Windows 10):
I would suggest checking for any errors, rather than ignoring them:
hr: HRESULT;
hr := DWM_EnableBlurBehind(GetConsoleWindow(), True);
OleCheck(hr);
Equivalently, you can avoid the need to check return values by using safecall calling convention (where the compiler will insert code to check the HRESULT and throw an exception if the function failed):
procedure DwmEnableBlurBehindWindow(hWnd: HWND; const pBlurBehind: DWM_BLURBEHIND); safecall; external 'dwmapi.dll' name 'DwmEnableBlurBehindWindow';//function to enable the glass effect
procedure DWM_EnableBlurBehind(hwnd : HWND; AEnable: Boolean; hRgnBlur : HRGN = 0; ATransitionOnMaximized: Boolean = False; AFlags: Cardinal = 1);
var
pBlurBehind : DWM_BLURBEHIND;
begin
pBlurBehind.dwFlags:=AFlags;
pBlurBehind.fEnable:=AEnable;
pBlurBehind.hRgnBlur:=hRgnBlur;
pBlurBehind.fTransitionOnMaximized:=ATransitionOnMaximized;
DwmEnableBlurBehindWindow(hwnd, pBlurBehind);
end;
Now, since you weren't checking errors anyway - you will now know the problem. On Windows 7 with desktop composition disabled, DwmEnableBlurBehindWindow returns:
0x80263001
{Desktop composition is disabled}
The operation could not be completed because desktop composition is disabled
Related
This question already has answers here:
How do you set the glass blend colour on Windows 10?
(3 answers)
Closed last year.
How do I create a acrylic blur effect like the one in UWP apps in a Delphi VCL application?
I tried using the following method I found here:
program DwmTest;
//Author : Rodrigo Ruz 2009-10-26
{$APPTYPE CONSOLE}
uses
Windows,
SysUtils;
type
DWM_BLURBEHIND = record
dwFlags : DWORD;
fEnable : BOOL;
hRgnBlur : HRGN;
fTransitionOnMaximized : BOOL;
end;
//function to enable the glass effect
function DwmEnableBlurBehindWindow(hWnd : HWND; const pBlurBehind : DWM_BLURBEHIND) : HRESULT; stdcall; external 'dwmapi.dll' name 'DwmEnableBlurBehindWindow';
//get the handle of the console window
function GetConsoleWindow: HWND; stdcall; external kernel32 name 'GetConsoleWindow';
function DWM_EnableBlurBehind(hwnd : HWND; AEnable: Boolean; hRgnBlur : HRGN = 0; ATransitionOnMaximized: Boolean = False; AFlags: Cardinal = 1): HRESULT;
var
pBlurBehind : DWM_BLURBEHIND;
begin
pBlurBehind.dwFlags:=AFlags;
pBlurBehind.fEnable:=AEnable;
pBlurBehind.hRgnBlur:=hRgnBlur;
pBlurBehind.fTransitionOnMaximized:=ATransitionOnMaximized;
Result:=DwmEnableBlurBehindWindow(hwnd, pBlurBehind);
end;
begin
try
DWM_EnableBlurBehind(GetConsoleWindow(), True);
Writeln('Test of glass effect');
Readln;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.
Unfortunately this only makes the windows a white-transparent appearance without any kind of blurring.
How can I achieve this effect?
First, you don't need to declare the DWM APIs yourself, since they are already declared in the DwmApi unit. Also, GetConsoleWindow is declared in the Windows unit.
Second, the effect your code is trying to apply is not the UWP effect; instead, it is the Windows Vista Aero effect.
And this does work for me:
program Project3;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows, System.SysUtils, DwmApi;
function DWM_EnableBlurBehind(hwnd: HWND; AEnable: Boolean; hRgnBlur: HRGN = 0; ATransitionOnMaximized: Boolean = False; AFlags: Cardinal = 1): HRESULT;
var
pBlurBehind: DWM_BLURBEHIND;
begin
pBlurBehind.dwFlags := AFlags;
pBlurBehind.fEnable := AEnable;
pBlurBehind.hRgnBlur := hRgnBlur;
pBlurBehind.fTransitionOnMaximized := ATransitionOnMaximized;
Result := DwmEnableBlurBehindWindow(hwnd, pBlurBehind);
end;
begin
DWM_EnableBlurBehind(GetConsoleWindow(), True);
Writeln('Hello, Aero!');
Readln;
end.
So why doesn't it work for you? Probably, you are using Windows 8 or later. In these systems, this effect has been removed.
Obviously, when you found this code, your first instinct was to look up the documentation for the DwmEnableBlurBehindWindow function. But apparently you missed the warning a page down:
Trying to implement events for Windows Core Audio API (Win7 64-bit Delphi XE5). My objective is to track the applications in the Volume Mixer to mute audio sessions that are not in my list and to adjust the volume for my target applications. I successfully enumerate the audio devices and the sessions, mute the audio and adjust the volume on a per-session basis but I am struggling with events. What I need is to get notified when new sessions are added and when sessions close so that I can enumerate again. I could use a timer to enumerate the session but I would prefer to avoid that.
The specific events that are not working are IAudioSessionNotification and IMMNotificationClient.
My questions are follows:
Is my approach to deriving classes for events too simplistic? I
found an example that is much more involved here:
Catch audio sessions events
, but it does not seem to work either (not tested personally)
Although IAudioEndpointVolumeCallback is "working" I think the code
smells because I am referencing UI elements in the OnNotify function
so I'd like some feedback/pointers. Is that a valid implementation?
I have two units: uAudioUI which contains the main form and MMDevApi unit that contains Core Audio interface.
The relevant parts of my code current looks like this (its a test app):
MMDevApi.pas
...
IAudioEndpointVolumeCallback = interface(IUnknown)
['{657804FA-D6AD-4496-8A60-352752AF4F89}']
function OnNotify(pNotify:PAUDIO_VOLUME_NOTIFICATION_DATA):HRESULT; stdcall;
end;
PIMMNotificationClient = ^IMMNotificationClient;
IMMNotificationClient = interface(IUnknown)
['{7991EEC9-7E89-4D85-8390-6C703CEC60C0}']
function OnDefaultDeviceChanged(const flow: EDataFlow; const role: ERole; const pwstrDefaultDevice: LPCWSTR):HRESULT; stdcall;
function OnDeviceAdded(const pwstrDeviceId: LPCWSTR):HRESULT; stdcall;
function OnDeviceRemoved(const pwstrDeviceId: LPCWSTR):HRESULT; stdcall;
function OnDeviceStateChanged(const pwstrDeviceID:LPCWSTR; const dwNewState: DWORD):HRESULT; stdcall;
function OnPropertyValueChanged(const pwstrDeviceID:LPCWSTR; const key: PROPERTYKEY):HRESULT; stdcall;
end;
IAudioSessionNotification = interface(IUnknown)
['{641DD20B-4D41-49CC-ABA3-174B9477BB08}']
function OnSessionCreated(const NewSession: IAudioSessionControl): HResult; stdcall;
end;
In the main form unit I derive classes for the required interfaces:
uAudioUI.pas
...
type
TEndpointVolumeCallback = class(TInterfacedObject, IAudioEndpointVolumeCallback)
public
function OnNotify(pNotify: PAUDIO_VOLUME_NOTIFICATION_DATA): HRESULT; stdcall;
end;
TMMNotificationClient = class(TInterfacedObject, IMMNotificationClient)
function OnDefaultDeviceChanged(const flow: EDataFlow; const role: ERole; const pwstrDefaultDevice: LPCWSTR):HRESULT; stdcall;
function OnDeviceAdded(const pwstrDeviceId: LPCWSTR):HRESULT; stdcall;
function OnDeviceRemoved(const pwstrDeviceId: LPCWSTR):HRESULT; stdcall;
function OnDeviceStateChanged(const pwstrDeviceID:LPCWSTR; const dwNewState: DWORD):HRESULT; stdcall;
function OnPropertyValueChanged(const pwstrDeviceID:LPCWSTR; const key: PROPERTYKEY):HRESULT; stdcall;
end;
TAudioMixerSessionCallback = class(TInterfacedObject, IAudioSessionEvents)
function OnDisplayNameChanged(NewDisplayName:LPCWSTR; EventContext:pGuid):HResult; stdcall;
function OnIconPathChanged(NewIconPath:LPCWSTR; EventContext:pGuid):HResult; stdcall;
function OnSimpleVolumeChanged(NewVolume:Single; NewMute:LongBool; EventContext:pGuid):HResult; stdcall;
function OnChannelVolumeChanged(ChannelCount:uint; NewChannelArray:PSingle; ChangedChannel:uint;
EventContext:pGuid):HResult; stdcall;
function OnGroupingParamChanged(NewGroupingParam, EventContext:pGuid):HResult; stdcall;
function OnStateChanged(NewState:uint):HResult; stdcall; // AudioSessionState
function OnSessionDisconnected(DisconnectReason:uint):HResult; stdcall; // AudioSessionDisconnectReason
end;
TAudioSessionCallback = class(TInterfacedObject, IAudioSessionNotification)
function OnSessionCreated(const NewSession: IAudioSessionControl): HResult; stdcall;
end;
For simplicity I use globals
private
{ Private declarations }
FDefaultDevice : IMMDevice;
FAudioEndpointVolume : IAudioEndpointVolume;
FDeviceEnumerator : IMMDeviceEnumerator;
FAudioClient : IAudioClient;
FAudioSessionManager : IAudioSessionManager2;
FAudioSessionControl : IAudioSessionControl2;
FEndpointVolumeCallback : IAudioEndpointVolumeCallback;
FAudioSessionEvents : IAudioSessionEvents;
FMMNotificationCallback : IMMNotificationClient;
FPMMNotificationCallback : PIMMNotificationClient;
FAudioSessionCallback : TAudioSessionCallback;
...
procedure TForm1.FormCreate(Sender: TObject);
var
...
begin
hr := CoCreateInstance(CLASS_IMMDeviceEnumerator, nil, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, FDeviceEnumerator);
if hr = ERROR_SUCCESS then
begin
hr := FDeviceEnumerator.GetDefaultAudioEndpoint(eRender, eConsole, FDefaultDevice);
if hr <> ERROR_SUCCESS then Exit;
//get the master audio endpoint
hr := FDefaultDevice.Activate(IID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, nil, IUnknown(FAudioEndpointVolume));
if hr <> ERROR_SUCCESS then Exit;
hr := FDefaultDevice.Activate(IID_IAudioClient, CLSCTX_ALL, nil, IUnknown(FAudioClient));
if hr <> ERROR_SUCCESS then Exit;
//volume handler
FEndpointVolumeCallback := TEndpointVolumeCallback.Create;
if FAudioEndpointVolume.RegisterControlChangeNotify(FEndPointVolumeCallback) = ERROR_SUCCESS then
FEndpointVolumeCallback._AddRef;
//device change / ex: cable unplug handler
FMMNotificationCallback := TMMNotificationClient.Create;
FPMMNotificationCallback := #FMMNotificationCallback;
if FDeviceEnumerator.RegisterEndpointNotificationCallback(FPCableUnpluggedCallback) = ERROR_SUCCESS then
FMMNotificationCallback._AddRef;
... and then finally, the class functions
{ TEndpointVolumeCallback }
function TEndpointVolumeCallback.OnNotify(pNotify: PAUDIO_VOLUME_NOTIFICATION_DATA): HRESULT;
var
audioLevel : integer;
begin
//NOTE: this works..
audioLevel := Round(pNotify.fMasterVolume * 100);
Form1.trackVolumeLevel.Position := audioLevel;
if pNotify.bMuted then
begin
form1.trackVolumeLevel.Enabled := False;
form1.spdMute.Caption := 'X';
end
else
begin
form1.trackVolumeLevel.Enabled := True;
form1.spdMute.Caption := 'O';
end;
Result := S_OK;
end;
{ TMMNotificaionClient }
function TMMNotificationClient.OnDefaultDeviceChanged(const flow: EDataFlow; const role: ERole; const pwstrDefaultDevice: LPCWSTR): HRESULT;
begin
//NOTE: this crashes - referencing a pointer to add 000000000
Form1.Label2.Caption := 'Audio device changed';
Result := S_OK;
end;
{ AudioMixerSessionCallback }
function TAudioMixerSessionCallback.OnSimpleVolumeChanged(NewVolume: Single; NewMute: LongBool; EventContext: PGUID): HRESULT;
begin
//NOTE: This works...
Form1.trackSessionVolumeLevel.Position := Round(NewVolume * 100);
Form1.Label2.Caption := EventContext.ToString;
Result := S_OK;
end;
{ AudioSessionCallback }
function TAudioSessionCallback.OnSessionCreated(const NewSession: IAudioSessionControl): HRESULT;
begin
//NOTE: This never gets called...
Form1.Label2.Caption := 'New audio session created';
Result := S_OK;
end;
I think the code is a translation from C/C++ ?
When using the TInterfacedObject, you don't need the _AddRef etc. methods, because the TInterfacedObject will handle those.
Another suggestion: I'm missing the threading implementation. Normally this is declared in the constructor or initialization section.
Example:
initialization
CoInitializeEx(Nil,
COINIT_APARTMENTTHREADED);
or
//Create method
inherited Create();
CoInitializeEx(Nil,
COINIT_APARTMENTTHREADED);
This is important when using an UI implementation. Otherwise you will not receive any events.
Non UI implementations (like drivers) should use the COINIT_MULTITHREADED model.
Some notes:
Instead of using pointers, like PGUID, use TGUID. When a field is declared in C++, it could be starting with ie pSingle. In Delphi this should be Single. When C++ is using pointer to pointers (like ppSingle) then - in most cases - in Delphi this would be a PSingle.
Also you declared function OnChannelVolumeChanged wrong.
It should be:
function OnChannelVolumeChanged(ChannelCount: UINT;
NewChannelArray: Array of Single;
ChangedChannel: UINT;
EventContext: TGUID): HResult; stdcall;
hello i try load dll into memory and play sound file from resources (Delphi2009). In this example i load dll from HDD to memory (i plan to load dll from resources to memory) but i got an error after Button1Click
First chance exception at $76E2C41F. Exception class EAccessViolation with message 'Access violation at address 00000000. Read of address 00000000'. Process DemoApp.exe (3020)
Sound doesn't play at all :/
some of code i used from here: http://www.cyberforum.ru/blogs/14360/blog1682.html#a_codemodez
but i couldn't compile it due to custom units strUtilz, MemModuleUnicode
BTMemoryModule v0.0.41 includes BTMemoryModule and also examples
http://code.google.com/p/memorymodule/downloads/list
BTMemoryModule v.1 (old probably) (with BTMemoryModule + BTMemoryModuleUnicode)
http://www.delphibasics.info/home/delphibasicssnippets/btmemorymodule
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, BTMemoryModule, StdCtrls, xpman;
const // Constants :::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::
_s = '';
_n=#13#10; // line break
ver = '1.0 '; // Articles
tit = 'Bass Memory App' + ver; // title - the name of the application
msgYN=$04; msgERR=$10; msgINF=$40; // <-type codes posts
res1='dll'; // resource name with dllkoy
res2='snd'; // name of the resource with sound
type // TYPES :::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::
MemRes = record // structure for the projection of the resource in memory
p: pointer; // pointer to the memory
sz: int64; // size (length)
rd: cardinal; // hResData
ri: cardinal; // hResInfo
end;
type
TBASS_ChannelPlay = function (handle: cardinal; restart: bool): bool; stdcall;
TBASS_StreamCreateFile = function (mem: bool; f: Pointer; offset, length: int64; flags: cardinal): cardinal; stdcall;
TBASS_StreamFree = function (handle: cardinal): bool; stdcall;
TBASS_Init = function (device: integer; freq, flags: cardinal; win: cardinal; clsid: pGUID): bool; stdcall;
TBASS_Free = function: bool; stdcall;
TForm1 = class(TForm)
BtnFileCAll: TButton;
BtnMemCall: TButton;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
mp_DllData : Pointer;
m_DllDataSize : Integer;
mp_MemoryModule: PBTMemoryModule;
//m_DllHandle: Cardinal;
m_BASS_ChannelPlay: TBASS_ChannelPlay;
m_BASS_StreamCreateFile: TBASS_StreamCreateFile;
//m_BASS_StreamFree: TBASS_StreamFree;
m_BASS_Init: TBASS_Init;
//m_BASS_Free: TBASS_Free;
public
{ Public declarations }
end;
var
Form1: TForm1;
wnd: cardinal; // window handle
ss: cardinal; // handle audio stream
snd: MemRes; // pointer to the audio file in memory
dll: MemRes; // pointer to memory dllku
bass: Pointer; // structure projection dll in memory
stp: word; // execution step (for debug)
st: boolean; // status of the audio stream
th: cardinal; // handle the flow of replacement buttons
ti: cardinal; // id flow
ms : TMemoryStream;
rs : TResourceStream;
implementation
{$R *.dfm}
{$R BassMem.RES} // snd CookieJarLoop.ogg RCData
function Res2Mem(hInst:cardinal;res:string;rtype:pChar):MemRes;
begin
result.p:=nil;
result.ri:=FindResource(hInst,pchar(res),rtype);
if result.ri=0 then exit;
result.sz:=SizeOfResource(hInst,result.ri);
if result.sz=0 then exit;
result.rd:=LoadResource(hInst,result.ri);
if result.rd=0 then exit;
result.p:=LockResource(result.rd);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
MemoryStream: TMemoryStream;
begin
Position := poScreenCenter;
MemoryStream := TMemoryStream.Create;
MemoryStream.LoadFromFile('bass.dll');
MemoryStream.Position := 0;
m_DllDataSize := MemoryStream.Size;
mp_DllData := GetMemory(m_DllDataSize);
MemoryStream.Read(mp_DllData^, m_DllDataSize);
MemoryStream.Free;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FreeMemory(mp_DllData);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
mp_MemoryModule := BTMemoryLoadLibary(mp_DllData, m_DllDataSize);
try
if mp_MemoryModule = nil then showmessage('err1');
#m_BASS_Init := BTMemoryGetProcAddress(mp_MemoryModule, 'BASS_Init');
if #m_BASS_Init = nil then showmessage('err2');
#m_BASS_ChannelPlay := BTMemoryGetProcAddress(mp_MemoryModule, 'BASS_ChannelPlay');
if #m_BASS_ChannelPlay = nil then showmessage('err3');
m_BASS_Init(-1, 44100, 0, Handle, nil);
snd:=Res2Mem(hInstance, res2 ,RT_RCDATA);
ss:=m_BASS_StreamCreateFile(true,snd.p,0,snd.sz,4{=BASS_SAMPLE_LOOP});
if ss=0 then showmessage('err ss=0');
m_BASS_ChannelPlay(ss, false);
except
Showmessage('An error occoured while loading the dll: ' + BTMemoryGetLastError);
end;
if mp_MemoryModule <> nil then BTMemoryFreeLibrary(mp_MemoryModule);
end;
end.
You do not initialise m_BASS_StreamCreateFile. Consequently it has the value nil when you call it. Which explains the error message.
You need to add a call to BTMemoryGetProcAddress to initialise m_BASS_StreamCreateFile.
#m_BASS_StreamCreateFile := BTMemoryGetProcAddress(mp_MemoryModule,
'BASS_StreamCreateFile');
if #m_BASS_StreamCreateFile = nil then ....
This would have been simple enough to discover had you run the code under the debugger. The exception would have been trapped by the debugger and the call stack will have led to the call of m_BASS_StreamCreateFile. You could then have inspected its value to discover that it was nil.
Well, first of all: Nafalem, your code is terrible =\
As David Heffernan said before - there are missing initialization for m_BASS_StreamCreateFile; but also: what did you expected to do with if mp_MemoryModule <> nil then MemFreeLibrary(mp_MemoryModule); just right after m_BASS_ChannelPlay???
Just think a bit - you starting to play sound and then removing library from memory...
You need to move MemFreeLibrary into FormDestory before FreeMemory(mp_DllData);.
But sadly, even fixing your code isn't enough to make it work.
As i said in my article (http://www.cyberforum.ru/blogs/14360/blog1682.html (sry, i'm too lazy to translate it to English)):
there are a bug inside the BTMemoryModule:
if (l_section.Characteristics and IMAGE_SCN_MEM_DISCARDABLE) <> 0 then begin
// section is not needed any more and can safely be freed
VirtualFree(Pointer(l_section.Misc.PhysicalAddress), l_section.SizeOfRawData, MEM_DECOMMIT);
inc(longword(l_section), sizeof(TImageSectionHeader));
continue;
end;
this part of code frees sections with enabled Discardable-flag, but it shouldn't be done in our case!
As you can find in msdn, discardable-flag means that section can be discarded as needed, as you see it CAN be discarded, not MUST be... and it's for physical PE-files, which could be readed from file on demand!
If speak more bout this, Discardable-flag was used in 16-bit Windows and it was saying that its contents may be not uploaded into the swap, and readed from a file, if necessary. In the 32-bit Win OS and higher versions system looks priorly at IMAGE_SCN_MEM_NOT_PAGED, so just leave discardable-flag to low-core driver development, and never use it in user-mode PE-modules.
P.S. >
i couldn't compile it due to custom units strUtilz, MemModuleUnicode
just download archive from my article, it contains MemModule with my fixes, as to strUtilz - just replace it with SysUtils, i wrote in comments that it's simply a module with str/int conversion-routines coded in asm.
//Sorry for my dirty English =P
As I can activate the glass effect on my console applications. I am using Windows 7 and Delphi 2010.
I found this application so it should be possible.
A couple of weeks ago I published this article on my blog.
The key is use the GetConsoleWindow and DwmEnableBlurBehindWindow functions.
The GetConsoleWindow function retrieves the window handle used by the console associated with the calling process.
The DwmEnableBlurBehindWindow function enables the blur effect (glass) on the provided window handle.
program ConsoleGlassDelphi;
{$APPTYPE CONSOLE}
uses
Windows,
SysUtils;
type
DWM_BLURBEHIND = record
dwFlags : DWORD;
fEnable : BOOL;
hRgnBlur : HRGN;
fTransitionOnMaximized : BOOL;
end;
function DwmEnableBlurBehindWindow(hWnd : HWND; const pBlurBehind : DWM_BLURBEHIND) : HRESULT; stdcall; external 'dwmapi.dll' name 'DwmEnableBlurBehindWindow';//function to enable the glass effect
function GetConsoleWindow: HWND; stdcall; external kernel32 name 'GetConsoleWindow'; //get the handle of the console window
function DWM_EnableBlurBehind(hwnd : HWND; AEnable: Boolean; hRgnBlur : HRGN = 0; ATransitionOnMaximized: Boolean = False; AFlags: Cardinal = 1): HRESULT;
var
pBlurBehind : DWM_BLURBEHIND;
begin
pBlurBehind.dwFlags:=AFlags;
pBlurBehind.fEnable:=AEnable;
pBlurBehind.hRgnBlur:=hRgnBlur;
pBlurBehind.fTransitionOnMaximized:=ATransitionOnMaximized;
Result:=DwmEnableBlurBehindWindow(hwnd, pBlurBehind);
end;
begin
try
DWM_EnableBlurBehind(GetConsoleWindow(), True);
Writeln('See my glass effect');
Writeln('Go Delphi Go');
Readln;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.
This is just a basic example; you must check the Windows OS version to avoid issues.
I have the service name for a windows service in delphi, and I know how to get the handle from that as well. What I need to do is stop a service, and if the stop fails for some reason I need to kill the process associated with the service. The problem is that I have multiple services running from the same executable, so I can't use the executable name to kill the process. This means I need the process id to kill the proper associated process. How can I get this id or some way to kill the proper process from the service name or handle?
QueryServiceStatusEx?
Please note I have only accepted this solution so that a full delphi code solution is accepted, all due thanks to Jk though for pointing me on the correct path.
--
Ok, I've been able to figure out how to use the answer by Jk and have come up with this solution in delphi.
For reference, this is the link provided by Jk:
QueryServiceStatusEx
My Solution:
unit Demo;
interface
uses
Windows, Forms, SysUtils,
StdCtrls, WinSvc, Controls, Classes;
type
//Form for basic demo usage
TForm6 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
end;
//Record defined for use as return buffer
_SERVICE_STATUS_PROCESS = record
dwServiceType: DWORD;
dwCurrentState: DWORD;
dwControlsAccepted: DWORD;
dwWin32ExitCode: DWORD;
dwServiceSpecificExitCode: DWORD;
dwCheckPoint: DWORD;
dwWaitHint: DWORD;
dwProcessId: DWORD;
dwServiceFlags: DWORD;
end;
//Function Prototype
function QueryServiceStatusEx(
SC_HANDLE: SC_Handle;
SC_STATUS_TYPE: Cardinal;
out lpBuffer: _SERVICE_STATUS_PROCESS;
cbBufSize: DWORD;
out pcbBytesNeeded: LPDWORD
): BOOL; stdcall;
//internal setup function
function GetPid(sService: String; sMachine: String = '') : Cardinal;
var
Form6: TForm6;
implementation
{$R *.dfm}
const
// windows api library
advapi32 = 'advapi32.dll';
//define the api call
function QueryServiceStatusEx; external advapi32 name 'QueryServiceStatusEx';
//for demo usage
procedure TForm6.Button1Click(Sender: TObject);
begin
Memo1.Lines.Add(IntToStr(Integer(GetPid('Service'))))
end;
function GetPid(sService: String; sMachine: String = '') : Cardinal;
var
schm,
schs: SC_Handle;
SC_STATUS_TYPE: Cardinal;
lpBuffer: _SERVICE_STATUS_PROCESS;
cbBufSize: DWORD;
pcbBytesNeeded: LPDWORD;
begin
//open the service manager (defined in WinSvc)
schm := OpenSCManager(PChar(sMachine), nil, SC_MANAGER_CONNECT);
//set the status type to SC_STATUS_PROCESS_INFO
//this is currently the only value supported
SC_STATUS_TYPE := $00000000;
//set the buffer size to the size of the record
cbBufSize := sizeof(_SERVICE_STATUS_PROCESS);
if (schm>0) then
begin
//grab the service handle
schs := OpenService(schm, PChar(sService), SERVICE_QUERY_STATUS);
if (schs>0) then
begin
//call the function
QueryServiceStatusEx(
schs,
SC_STATUS_TYPE,
lpBuffer,
cbBufSize,
pcbBytesNeeded);
CloseServiceHandle(schs);
end;
CloseServiceHandle(schm);
end;
Result := lpBuffer.dwProcessId;
end;
end.
Please note that not all external naming and other necessities are included.
Or use DSiWin32 for many useful functions, including DSiGetProcessID. This code was written by StackOverflow user (and programmer) Gabr.
Here's the function, for your own reference. It will give you what you are looking for:
//Retrieves ID of the specified process. Requires Toolhelp API.
// #returns False if ID cannot be retrieved. Check GetLastError - if it is 0, process
// doesn't exist; otherwise it contains the Win32 error code.
// #author gabr
// #since 2004-02-12
//
function DSiGetProcessID(const processName: string; var processID: DWORD): boolean;
var
hSnapshot: THandle;
procEntry: TProcessEntry32;
begin
Result := false;
hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if hSnapshot = 0 then
Exit;
try
procEntry.dwSize := Sizeof(procEntry);
if not Process32First(hSnapshot, procEntry) then
Exit;
repeat
if AnsiSameText(procEntry.szExeFile, processName) then begin
processID := procEntry.th32ProcessID;
Result := true;
break; // repeat
end;
until not Process32Next(hSnapshot, procEntry);
finally DSiCloseHandleAndNull(hSnapshot); end;
end; { DSiGetProcessID }