How can I force my Program to use the strongest Graphic card [duplicate] - delphi

I want my application to always run using the real gpu on nVidia Optimus laptops.
From "Enabling High Performance Graphics Rendering on Optimus Systems", (http://developer.download.nvidia.com/devzone/devcenter/gamegraphics/files/OptimusRenderingPolicies.pdf):
Global Variable NvOptimusEnablement (new in Driver Release 302)
Starting with the Release 302 drivers, application developers can
direct the Optimus driver at runtime to use the High Performance
Graphics to render any application–even those applications for which
there is no existing application profile. They can do this by
exporting a global variable named NvOptimusEnablement. The Optimus
driver looks for the existence and value of the export. Only the LSB
of the DWORD matters at this time. A value of 0x00000001 indicates
that rendering should be performed using High Performance Graphics. A
value of 0x00000000 indicates that this method should be ignored.
Example Usage:
extern "C" { _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; }
The problem is that I want to do this using Delphi. From what I've read Delphi does not support export of variables even though some hacks exists. I did try a few of them but couldn't make it work.
In the same nvidia document I read that forcing the proper GPU can be accomplished via linking statically to one of a handful listed dlls. But I don't want to link to dlls I'm not using. (Why the opengl.dll is not one of them is beyond me.) A simple exported variable seems much cleaner.

From what I've read Delphi does not support export of variables.
That statement is incorrect. Here's the simplest example that shows how to export a global variable from a Delphi DLL:
library GlobalVarExport;
uses
Windows;
var
NvOptimusEnablement: DWORD;
exports
NvOptimusEnablement;
begin
NvOptimusEnablement := 1;
end.
I think your problem is that you wrote it like this:
library GlobalVarExport;
uses
Windows;
var
NvOptimusEnablement: DWORD=1;
exports
NvOptimusEnablement;
begin
end.
And that fails to compile with this error:
E2276 Identifier 'NvOptimusEnablement' cannot be exported
I don't understand why the compiler doesn't like the second version. It's probably a bug. But the workaround in the first version is just fine.

I'm not a Delphi expert, but AFAIK it is possible to link to static libraries implemented in C from Delphi. So I'd simply create a small stub library, just providing this export, which is statically linked into your Delphi program. This adds the very export you need.

Related

SAPI 5.4/11 Japanese TTS in Delphi GUI vs console

Trying to use MS Speech API v11 with a Japanese engine (MS Haruka) in Delphi 10.3.
I have a sample app with a form and a button. The click handler goes:
uses SpeechLib11_TLB; // Imported from "Microsoft Speech Object Library" v.B.0
procedure TForm1.Button1Click(Sender: TObject);
var
v: ISpeechVoice;
begin
v := CoSpVoice.Create();
//5.4 only but won't hurt
v.Voice := v.GetVoices('language=411', '').Item(0);
v.Speak('時間', SVSFDefault);
end;
That causes an error, "Catastrophic failure" (HRESULT 0x8000FFFF, E_UNEXPECTED). The code that I think should be equivalent works in a C++ project:
#include <windows.h>
#import "libid:d3c4a7f2-7d27-4332-b41f-593d71e16db1" rename_namespace("SAPI") //v11
//#import "libid:C866CA3A-32F7-11D2-9602-00C04F8EE628" rename_namespace("SAPI") //v5.4
int wmain()
{
CoInitializeEx(0, COINIT_APARTMENTTHREADED);
{
SAPI::ISpeechVoicePtr v;
v.CreateInstance(__uuidof(SAPI::SpVoice));
//Needed for 5.4 only, but won't hurt
SAPI::ISpeechObjectTokensPtr voices(v->GetVoices(L"language=411", L""));
v->Voice = voices->Item(0);
v->Speak(L"時間", SAPI::SVSFDefault);
}
CoUninitialize();
return 0;
}
That works and speaks. So the SAPI per se is not broken on the machine. The platform is Win32 in both projects, not Win64. The Japanese voice is the default one (no need to set it explicitly).
Same result with SAPI 5.4 proper (not OneCore), although the Japanese voice is not the default one and I had to add a couple of lines to set it as the default.
Further debugging reveals that on the Delphi side, as much as calling the v.Voice property getter immediately after the first line causes the same error, E_UNEXPECTED. Meanwhile, the Voice setter works if you pass it a valid voice token object from GetVoices(). It looks as if the voice object initializes itself to its defaults correctly in C++, but somehow skips that in the Delphi project.
Requesting v.Voice right after construction works though in Delphi with SAPI 5.4. Calling Speak() still throws a E_UNEXPECTED.
What could be the difference in process/threadwide execution context between C++ and Delphi? It's not the thread locale. The COM thread model is apartment in both.
The same Delphi code works with an English phrase and an English voice (MS Helen). So whatever init failure there might be, it's probably specific to Haruka.
The SAPI 11 runtime is available here. The language data for TTS are here.
Another data point. I've rewritten the SAPI logic in Delphi to use SAPI 5.4 OneCore instead (not SAPI 5.4 proper). Unlike 5.4 and 11, it doesn't expose an IDispatch-based interface, and it's somewhat clumsier specifically in Delphi, but Japanese TTS works. The question, as initially posed, is still unanswered, but at least there's a workaround. I'll write up an answer, but I won't accept it.
However, it's not the custom vs. dual distinction that's to blame. I've changed the logic to use custom interfaces instead of automation ones with SAPI 5.4 proper (the typelib defines both), still got E_UNEXPECTED from Speak(). There's no error info.
Here's another beautiful data point: SAPI 5.4 TTS with automation based API works and talks as expected in a Delphi console app. So it's not even Delphi specific, it's somehow VCL specific. What is it with Delphi GUI? Needless to say, I immediately retested the C++ snippet in a C++ GUI application, with a form and a button. The C++ one talks.
Not an answer, but a workaround.
Windows 10 comes with two flavors of 32-bit SAPI. There's SAPI 5.4 proper (in system32\speech), and also SAPI 5.4 OneCore (in system32\speech_onecore). The latter, even though it's superficially the same, exposes a different typelib - there's no automation support, all interfaces are custom instead of dual. What's more important, when you download the Japanese TTS voice in the Windows 10 Settings app, you end up with 3 voices under OneCore (Sayaka, somehow, missing) and only one, Haruka, under 5.4 proper.
Delphi can consume custom interfaces in a typelib, but the methods look somewhat clumsier. Also, the enumeration of voices in the automation API is cleaner. Anyway, here goes.
uses SpeechLib54Core_TLB; // This time it's OneCore
procedure TForm1.Button1Click(Sender: TObject);
var
v: ISpVoice;
cat: ISpObjectTokenCategory;
toks: IEnumSpObjectTokens;
tok: ISpObjectToken;
sno: LongWord;
hr: HResult;
n: Cardinal;
begin
v := CoSpVoice.Create();
hr := v.GetVoice(tok);
tok.GetCategory(cat);
cat.EnumTokens('language=411', '', toks); //411 means Japanese
toks.GetCount(n);
if n = 0 then
exit; // No Japanese voices installed
toks.Item(0, tok); //Take the first one - typically Ayumi
v.SetVoice(tok);
v.Speak('時間', 0, sno);
end;
Note that passing a Japanese string literal to a COM method works without an explicit cast to a wide string.

Delphi embed DLL into executable without use of resources

I want do exactly this:
embed DLL into EXE
but without using of resources (the DLL binary should not be visible in resource viewer but stay hidden inside of the executable code).
I tried to convert the file into string literal(s) but the file is too big and I only get out of memory or stack overflow exceptions when trying to compile it:
const cFileSize = 2424564;
const cFileBlock =
'30820274020100300D06092A864886F70D010101'+
'05000482025E3082025A02010002818100D713B2'+
...
'BF1F8167F517D3945C27CABCB1E7D7C4092336B9';
What do you suggest:
a)try some means to meet compiler memory limitations (like split to more include files etc.)?
b)convert the DLL to object file and link it with the application (which tool?)
c)some other way?
Thank you
I can confirm that solution proposed in the comments above works:
const cFileBlock: array[0..2424564-1] of byte = ($30, $82, ..., $B9);
The compiler does not complain about stack overflows and out of memory errors anymore.
But I will not use this solution anyway because of possible false threat warnings from antivirus software, see the comments above again.
Thank you all for help.
Why not just use a CRC checksum ?
If your goal is to ensure that the DLL has not been tampered with in any way, you can store a CRC in your program which is calculated from a known untampered DLL. Then later, simply read in the DLL and compare the calculated checksum of that DLL with what you have stored.
One thing to watch out for is if the person/company that produces the DLL makes a change, then a different checksum will result and this updated checksum will need to be stored in your application or else the program will "believe" the DLL has been tampered with if the updated version is used.

Unit source code does not match code execution path when breakpoint hit

I am debugging a DirectShow filter I created with the DSPACK code library using Delphi 6 Pro. When a breakpoint I set is hit in one particular unit named BaseClass.pas, and I begin tracing, the Execution Point jumps to strange places in the source code. This usually indicates that the source code being traced does not match the source code that was compiled into one of the packages being used by the Delphi application. Oddly enough it is only the BaseClass unit since I have traced other units belonging to the DSPACK code library and they do not exhibit this problem. I am not using run-time packages.
I scanned my disk and found only one copy of BaseClass.dcu with a modification date equal to the last time I built the program. I have not modified the source for that unit or any other belonging to DSPACK. Since my Filter is part of the main application this indicates that BaseClass.pas would be subject to a dual use situation since it is used to build the DSPACK component package (dpk), and is also referenced by my main application directly via the TBCSource object my Filter descends from. Note, I did try adding the unit PAS file directly to my Project but that didn't fix anything.
I also went back and re-opened each of the DSPACK package files and did a full re-build. None of this helped. Is there something else I can try to get the source synchronized with the compiled image of the BaseClass unit? Or is a different problem altogether and if so, what is it and how can I fix it?
Sometimes this happens when code is copied/pasted from web pages or other sources, and the lines don't end with CR/LF pairs (#13#10 or 0x0D0A, standard for Windows) but end in only LF (#10 or 0x0A, typically the line ending in *nix systems) or CR (#13 or 0x0D, typical with Mac OSX/iOS). The incorrect line terminators confuse the debugger - this has been an issue for the past several Delphi versions.
You can sometimes fix this by opening the source file using a text editor like Notepad, making a small meaningless change (insert and then delete a blank line, for instance), and then save the file.
I had same problem and made a similar utility. Fixed it.
Basically, just this:
procedure adjustCRLF(filename : String);
var
strList : TStringList;
begin
strList := TStringList.Create;
try
strList.LoadFromFile(filename);
strList.Text := AdjustLineBreaks(strList.Text);
strList.SaveToFile(filename);
finally
strList.Free;
end;
end;
There is another way this can happen: if the IDE erroneously opens another source file with the same name (but different, such as an earlier version) then all the debug points will be incorrect, and the debugger will even allow you to step through the incorrect file.
I've seen Delphi 7 do this once.
Make sure that when you rebuild it, that in the compiler options for your project that you have "Debug Information" turned on. In fact, most of the options under Debugging should be set in your project's Compiler options.
Also, if you haven't already, restart Delphi.

How to redirect registry access of a dll loaded by my program

I have got a dll that I load in my program which reads and writes its settings to the registry (hkcu). My program changes these settings prior to loading the dll so it uses the settings my program wants it to use which works fine.
Unfortunately I need to run several instances of my program with different settings for the dll. Now the approach I have used so far no longer works reliably because it is possible for one instance of the program to overwrite the settings that another instance just wrote before the dll has a chance to read them.
I haven't got the source of the dll in question and I cannot ask the programmer who wrote it to change it.
One idea I had, was to hook registry access functions and redirect them to a different branch of the registry which is specific to the instance of my program (e.g. use the process id as part of the path). I think this should work but maybe you have got a different / more elegant.
In case it matters: I am using Delphi 2007 for my program, the dll is probably written in C or C++.
As an alternative to API hooking, perhaps you could use RegOverridePredefKey API.
Instead of hooking the registry access for the dll, you can use an inter-process lock mechanism for writing the values to the registry for your own app. The idea being that the lock acquired by instance1 isn't released until its dll "instance" has read the values, so that when instance2 starts it won't acquire the lock until instance1 has finished. You'd need a locking mechanism that works between processes for this to work. For example mutexes.
To create mutexes:
procedure CreateMutexes(const MutexName: string);
//Creates the two mutexes checked for by the installer/uninstaller to see if
//the program is still running.
//One of the mutexes is created in the global name space (which makes it
//possible to access the mutex across user sessions in Windows XP); the other
//is created in the session name space (because versions of Windows NT prior
//to 4.0 TSE don't have a global name space and don't support the 'Global\'
//prefix).
const
SECURITY_DESCRIPTOR_REVISION = 1; // Win32 constant not defined in Delphi 3
var
SecurityDesc: TSecurityDescriptor;
SecurityAttr: TSecurityAttributes;
begin
// By default on Windows NT, created mutexes are accessible only by the user
// running the process. We need our mutexes to be accessible to all users, so
// that the mutex detection can work across user sessions in Windows XP. To
// do this we use a security descriptor with a null DACL.
InitializeSecurityDescriptor(#SecurityDesc, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(#SecurityDesc, True, nil, False);
SecurityAttr.nLength := SizeOf(SecurityAttr);
SecurityAttr.lpSecurityDescriptor := #SecurityDesc;
SecurityAttr.bInheritHandle := False;
CreateMutex(#SecurityAttr, False, PChar(MutexName));
CreateMutex(#SecurityAttr, False, PChar('Global\' + MutexName));
end;
To release a mutex, you'd use the ReleaseMutex API and to acquire a created mutex, you'd use the OpenMutex API.
For CreateMutex see: http://msdn.microsoft.com/en-us/library/ms682411(VS.85).aspx
For OpenMutex see: http://msdn.microsoft.com/en-us/library/ms684315(v=VS.85).aspx
For ReleaseMutex see: http://msdn.microsoft.com/en-us/library/ms685066(v=VS.85).aspx
dirty method: open the dll in a hexeditor and change/alter the registry-path from the original hive to any other you want to use or have your proper settings.

ZeroConf/Bonjour Code that works in Delphi 7 not working in 2009

I have the following declaration for DNSServiceRegister:
function DNSServiceRegister
(
var sdRef: TDNSServiceRef;
const flags: TDNSServiceFlags;
const interfaceIndex: uint32_t;
const name: PUTF8String; //* may be NULL */
const regType: PUTF8String;
const domain: PUTF8String; //* may be NULL */
const host: PUTF8String; //* may be NULL */
const port: uint16_t;
const txtLen: uint16_t;
const txtRecord: Pointer; //* may be NULL */
const callBack: TDNSServiceRegisterReply; //* may be NULL */
const context: Pointer //* may be NULL */
): TDNSServiceErrorType; stdcall; external DNSSD_DLL;
In my Bonjour framework I have the following response to an announced service being made active (i.e. to actually start announcing itself, via Bonjour):
procedure TAnnouncedService.Activate;
var
flags: Cardinal;
name: UTF8String;
svc: UTF8String;
pn: PUTF8String;
ps: PUTF8String;
begin
fPreAnnouncedServiceName := ServiceName;
inherited;
if AutoRename then
flags := 0
else
flags := kDNSServiceFlagsNoAutoRename; { - do not auto-rename }
if (ServiceName <> '') then
begin
name := ServiceName;
pn := PUTF8String(name);
end
else
pn := NIL;
svc := ServiceType;
ps := PUTF8String(svc);
CheckAPIResult(DNSServiceRegister(fHandle,
flags,
0 { interfaceID - register on all interfaces },
pn,
ps,
NIL { domain - register in all available },
NIL { hostname - use default },
ReverseBytes(Port),
0 { txtLen },
NIL { txtRecord },
DNSServiceRegisterReply,
self));
TBonjourEventHandler.Create(fHandle);
end;
This is more verbose than I think it strictly needs to be, certainly it was working perfectly well in Delphi 7 in a much less verbose form. I have expanded a lot of operations into explicit steps to facilitate debugging, e.g. to be able to identify any implicit transforms of string payloads that may be occuring "under the hood" in Delphi 2009.
Even in this untidy expanded form this code compiles and works perfectly well in Delphi 7, but if I compile and run with Delphi 2009 I get no announcement of my service.
For example, if I run this code as part of a Delphi 7 application to register a _daap._tcp service (an iTunes shared library) I see it pop-up in a running instance of iTunes. If I recompile the exact same application without modification in Delphi 2009 and run it, I do not see my service appearing in iTunes.
I get the same behaviour when monitoring with the dns-sd command line utility. That is, service code compiled with Delphi 7 behaves as I expect, compiled in Delphi 2009 - nothing.
I am not getting any errors from the Bonjour API - the DNSServiceRegisterReply callback is being called with an ErrorCode of 0 (zero), i.e. success, and if I supply a NIL name parameter with AutoRename specified in the flags then my service is allocated the correct default name. But still the service does not show up in iTunes.
I am at a loss as to what is going on.
As you might be able to tell from the expansion of the code, I have been chasing potential errors being introduced by the Unicode implementation in Delphi 2009, but this seems to be leading me nowhere.
The code was originally developed against version 1.0.3 of the Bonjour API/SDK. I've since updated to 1.0.6 in case that was somehow involved, without any success. afaict 1.0.6 merely added a new function for obtaining "properties", which currently supports only a "DaemonVersion" property for obtaining the Bonjour version - this is working perfectly.
NOTE: I'm aware that the code as it stands is not technically UTF8-safe in Delphi 7 - I have eliminated explicit conversions as far as possible so as to keep things as simple as possible for the automatic conversions that Delphi 2009 applies. My aim now is to get this working in Delphi 2009 then work backward from that solution to hopefully find a compatible approach for earlier versions of Delphi.
NOTE ALSO: I originally also had problems with browsing for advertised services, i.e. identifying an actual iTunes shared library on the network. Those issues were caused by the Unicode handling in Delphi 2009 and have been resolved. My Delphi 2009 code is just as capable of identifying an actual iTunes shared library and querying it's TXT records. It's only this service registration that isn't working.
I must be missing something stupid and obvious.
Does anyone have any ideas?!
UPDATE
Having returned to this problem I have now discovered the following:
If I have a pre-D2009 and a D2009+ IDE open (e.g D2006 and D2010) with the same project loaded into both IDE's concurrently:
Build and run under 2006: It works - my service announcement is picked up by iTunes
Switch to D2010 and run (without building): It does a minimal compile, runs and works.
Do a full build in D2010: It stops working
Switch back to D2006 and run (without building): It doesn't work
Do a full build in D2006: It works again
Does this give anyone any other ideas?
The answer to this is mind boggling. On the one hand I made a completely stupid, very simple mistake, but on the other hand it should never - as far as I can see - have worked in ANY version of Delphi!
The problem was nothing what-so-ever to do with the Unicode/non-unicodeness of any strings, but was actually due to a type mismatch in the PORT parameter.
I was passing in the result of ReverseBytes(Port) - that parameter expected a uint16_t, i.e. a Word value. My Port property was however declared (lazily) as an Integer!!
Once I fixed this and had Port declared as a Word, it now works on both D2007- and D2009+ versions of Delphi.
Very weird.
I can only think that some other edge-case behaviour of the compiler that might have somehow affected this was changed when Unicode support was introduced.
Based on the information that we have available here, the situation is this:
When calling the DLL with your code in Delphi 2007, it gives one result.
When calling the same DLL with your code in Delphi 2009, it gives another result.
The suspicion is, that it is related to the Delphi 2009 compiler.
Logically, the difference must therefore be, that Delphi 2009 sends different values as parameters. In order to make the debugging truly Delphi-independent, you therefore need to create a dummy DLL, which reports the values it gets. Other Delphi-dependent methods may be applied, like looking at the disassembly of the function-call into the DLL, and debugging it so that we know exactly what values are passed, and how, to the DLL, in both compilers.
I can't find the declaration instruction for the vars "ServiceName" and "ServiceType" in your code sample.
Assuming a String type (thus a unicode string), I guess (yes... no D2009 available to test this) lazy typecasting could be an issue:
name := ServiceName;
Why not use the following?
name := PAnsiChar(AnsiString(ServiceName))
Anyhow... just my 2 cts.
BTW:
I always use the pre defined "EmptyStr", "EmptyWideStr" ... so the test would look like:
if (ServiceName <> EmptyStr) then
which should be safe and avoid the confusion of types.
On the other side, Delphi may interpret the '' as an ANSIChar like the following declaration do:
const
MyParagraphChar = '§';
Not sure... I'm confused - should go home now ;)
If the DLL is not written using Delphi 2009, you may want to use something else than PUTF8String. The Delphi 2009 Utf8String type is different from Delphi 2007's UTF8String type.
If the DLL was written using C/C++, I strongly suggest to use PAnsiChar() instead of PUtf8String.

Resources