The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,861 other subscribers

Archive for July, 2021

delphi – How to enable wirecompression on Firebird 3.0 – Stack Overflow

Posted by jpluimers on 2021/07/08

For my link archive:

–jeroen

Posted in Database Development, Delphi, Development, Firebird, Software Development | Leave a Comment »

Case sensitivity for SQL identifiers · ontop/ontop Wiki · GitHub

Posted by jpluimers on 2021/07/08

For my link archive: [WayBack] Case sensitivity for SQL identifiers · ontop/ontop Wiki · GitHub:

  • Oracle and H2 changes unquoted identifiers to uppercase.
    Although technically possible, Oracle explicitly recommends to not use lowercase identifers. We do not support H2 with the setting DATABASE_TO_UPPER=FALSE, if this setting is enabled all queries with names and tables in lowercase must be quoted.
  • DB2 Names are not case sensitive.
    For example, the table names CUSTOMER and Customer are the same, but object names are converted to uppercase when they are entered. If a name is enclosed in quotation marks, the name becomes case sensitive. The schema name is case-sensitive, and must be specified in uppercase characters.
  • Postgres changes unquoted identifiers (both columns and alias names) to lowercase.
  • Mysql does not change the case of unquoted tables and schemas.
    It changes in lowercase the unquoted columns. Mysql tables are stored as files in the operating system the server runs on. This means that database and table names are not case sensitive in Windows, and case sensitive in most varieties of Unix or Linux. The backtick ` is used for enclosing identifiers such as table and column names.
  • Mssqlserver All connection string property names are case-insensitive.
    For example, Password is the same as password. Identifiers of objects in a database, such as tables, views, and column names, are assigned the default collation of the database. For example, two tables with names that differ only in case can be created in a database that has case-sensitive collation, but cannot be created in a database that has case-insensitive collation. Default SQL Server is not case sensitive. SELECT * FROM SomeTable is the same as SeLeCT * frOM soMetaBLe. Delimited identifiers are enclosed in double quotation marks (“) or brackets ([]). Identifiers that comply with the rules for the format of identifiers may or may not be delimited.

–jeroen

Posted in Database Development, DB2, Development, MySQL, OracleDB, PostgreSQL, SQL Server | Leave a Comment »

E2213 Bad packaged unit format: ..\xxxxx.dcp.yyyy – Expected version: 32.0, Windows Unicode(x86) Found version: 105.101, Unk(CIL)

Posted by jpluimers on 2021/07/08

On my research list I have seen this happen with various libraries, but only libraries that deliver a single set of .bpl/.dcp files that you require for both debug and release builds.

The error occurs both ways:

  • building a “debug” build is fine, but after it a “release” build fails
  • building a “release” build is fine, but after it a “debug” build fails

This is with all separate DCU output directories for any permutation in any project: .\$(Platform)\$(Config)\$(SanitizedProjectName)

Example (where xxxx.pas is the first unit depending on Qrctrls, but I have seen it with other libraries that provide .bpl/.dcp combinations as well):

[dcc32 Fatal Error] xxxx.pas(14): E2213 Bad packaged unit format: ..\3rdParty\Quickrep506\19.0\Lib\Win32\Release\QR506RunDXE10_2.dcp.Qrctrls - Expected version: 32.0, Windows Unicode(x86) Found version: 105.101, Unk(CIL)

My best guess is that something is being cached in between builds, but not marked for the correct build configuration well enough.

–jeroen

Posted in Delphi, Delphi 10.2 Tokyo (Godzilla), Development, Software Development | Leave a Comment »

During software quality courses, I always explain to avoid abbreviations and acronyms as they are very domain specific. It seems authz, authn differ. As do a11n,

Posted by jpluimers on 2021/07/07

Each time I teach or talk about software quality, I stress that you should not use abbreviations nor acronyms as they confuse people and make communication a lot harder.

This is not just because acronyms and abbreviations are domain specific, which makes it harder to switch domains, but also because it raises the level for people coping with things like wordblindness or dyslexia.

Recently, two new abbreviations seem to have popped up: authn and authz (don’t you love it that Wikipedia has links for them, but does not explain them?). At first I thought it had something to do with who authored some bits of a system. But I was wrong:

[WayBack] Ian Coldwater 📦💥✨ on Twitter: “authn == authentication authz == authorization… “

For an all-inclusion point of view, I was amazed at for instance a11n, and I am not alone:

[WayBack] Thread by @MattGrayYES: “Here’s a question: When I see people tweet about accessibility they hashtag . What links allies to accessibility? Googling didn’t help […]” #ally

Here’s a question: When I see people tweet about accessibility they hashtag #ally. What links allies to accessibility?
Googling didn’t help

Hahaha apparently it’s a11y not ally, as an abbreviation of accessibility. Is that ironic or what. How is anyone meant to know that‽

Apparently some people can’t be bothered to write the eleven letters between the a and the y, so swap it for “11”
Now I think of it, writing like that is so easy to read!
I3l f3d b7t: h2h b4s, s6s, b3n, b3k p5g a1d b3d b3s.

Add to that things like l10n or i18n, and dozens of other abbreviations and slowly your brain will start to melt until you realise it is too late.

So pick up your autocorrect, typing completion and other automation systems and lets get rid of acronyms and abbreviations.

Because we deserve better.

–jeroen

Read the rest of this entry »

Posted in Agile, Code Quality, Development, Software Development | Leave a Comment »

SetProcessWorkingSetSize: you hardly – if ever – need to call this from your process

Posted by jpluimers on 2021/07/07

There are quite a few posts that recommend using SetProcessWorkingSetSize to trim your process working set, usually in the SetProcessWorkingSetSize(ProcessHandle, -1, -1) form:

[WayBack] SetProcessWorkingSetSize function (winbase.h) | Microsoft Docs

Sets the minimum and maximum working set sizes for the specified process.

BOOL SetProcessWorkingSetSize(
  HANDLE hProcess,
  SIZE_T dwMinimumWorkingSetSize,
  SIZE_T dwMaximumWorkingSetSize );

The working set of the specified process can be emptied by specifying the value (SIZE_T)–1 for both the minimum and maximum working set sizes. This removes as many pages as possible from the working set. The [WayBack] EmptyWorkingSet function can also be used for this purpose.

In practice you hardly ever have to do this, mainly because this will write – regardless of (dis)usage – all of your memory to the pagefile, even the memory your frequently use.

Windows has way better heuristics to do that automatically for you, skipping pages you frequently use.

It basically makes sense in a few use cases, for instance when you know that most (like 90% or more) of that memory is never going to be used again.

Another use case (with specific memory sizes) is when you know that your program is going to use a defined range of memory, which is outside what Windows will heuristically expect from it.

A few more links that go into more details on this:

  • [WayBack] windows – Pros and Cons of using SetProcessWorkingSetSize – Stack Overflow answers by:
    • Hans Passant:

      SetProcessWorkingSetSize() controls the amount of RAM that your process uses, it doesn’t otherwise have any affect on the virtual memory size of your process. Windows is already quite good at dynamically controlling this, swapping memory pages out on demand when another process needs RAM.

      By doing this manually, you slow down your program a lot, causing a lot of page faults when Windows is forced to swap the memory pages back in.

      SetProcessWorkingSetSize is typically used to increase the amount of RAM allocated for a process. Or to force a trim when the app knows that it is going to be idle for a long time. Also done automatically by old Windows versions when you minimize the main window of the app.

    • Zack Yezek:

      The only good use case I’ve seen for this call is when you KNOW your process is going to hog a lot of the system’s RAM and you want to reserve it for the duration. You use it to tell the OS “Yes, I’m going to eat a lot of the system RAM during my entire run and don’t get in my way”.

    • Maxim Masiutin:

      We have found out that, for a GUI application written in Delphi for Win32/Win64 or written in a similar way that uses large and heavy libraries on top of the Win32 API (GDI, etc), it is worth calling SetProcessWorkingSetSize once.

      We call it with -1, -1 parameters, within a fraction of second after the application has fully opened and showed the main window to the user. In this case, the SetProcessWorkingSetSize(... -1, -1) releases lots of startup code that seem to not needed any more.

  • [WayBack] c# – How to set MinWorkingSet and MaxWorkingSet in a 64-bit .NET process? – Stack Overflow answer by Hans Passant:

    Don’t pinvoke this, just use the Process.CurrentProcess.MinWorkingSet property directly.

    Very high odds that this won’t make any difference. Soft paging faults are entirely normal and resolved very quickly if the machine has enough RAM. Takes ~0.7 microseconds on my laptop. You can’t avoid them, it is the behavior of a demand_paged virtual memory operating system like Windows. Very cheap, as long as there is a free page readily available.

    But if it “blips” you program performance then you need to consider the likelihood that it isn’t readily available and triggered a hard page fault in another process. The paging fault does get expensive if the RAM page must be stolen from another process, its content has to be stored in the paging file and has to be reset back to zero first. That can add up quickly, hundreds of microseconds isn’t unusual.

    The basic law of “there is no free lunch”, you need to run less processes or buy more RAM. With the latter option the sane choice, 8 gigabytes sets you back about 75 bucks today. Complete steal.

  • [WayBack] c++ – SetProcessWorkingSetSize usage – Stack Overflow answer by MSalters:

    I had an application which by default would close down entirely but keep listening for certain events. However, most of my code at that point would not be needed for a long time. To reduce the impact my process made, I called SetProcessWorkingSetSize(-1,-1);. This meant Windows could take back the physical RAM and give it to other apps. I’d get my RAM back when events did arrive.

    That’s of course unrelated to your situation, and I don’t think you’d benefit.

  • [WayBack] delphi – When to call SetProcessWorkingSetSize? (Convincing the memory manager to release the memory) – Stack Overflow

    If your goal is for your application to use less memory you should look elsewhere. Look for leaks, look for heap fragmentations look for optimisations and if you think FastMM is keeping you from doing so you should try to find facts to support it. If your goal is to keep your workinset size small you could try to keep your memory access local. Maybe FastMM or another memory manager could help you with it, but it is a very different problem compared to using to much memory.

    you can check the FasttMM memory usage via FasttMM calls GetMemoryManagerState and GetMemoryManagerUsageSummary before and after calling API SetProcessWorkingSetSize.

    I don’t need to use SetProcessWorkingSetSize. FastMM will eventually release the RAM.


    To confirm that this behavior is generated by FastMM (as suggested by Barry Kelly) I crated a second program that allocated A LOT of RAM. As soon as Windows ran out of RAM, my program memory utilization returned to its original value.

  • [WayBack] delphi – SetProcessWorkingSetSize – What’s the catch? – Stack Overflow answer by Rob Kennedy:

    Yes, it’s a bad thing. You’re telling the OS that you know more about memory management than it does, which probably isn’t true. You’re telling to to page all your inactive memory to disk. It obeys. The moment you touch any of that memory again, the OS has to page it back into RAM. You’re forcing disk I/O that you don’t actually know you need.

    If the OS needs more free RAM, it can figure out which memory hasn’t been used lately and page it out. That might be from your program, or it might be from some other program. But if the OS doesn’t need more free RAM, then you’ve just forced a bunch of disk I/O that nobody asked for.

    If you have memory that you know you don’t need anymore, free it. Don’t just page it to disk. If you have memory that the OS thinks you don’t need, it will page it for you automatically as the need arises.

    Also, it’s usually unwise to call Application.ProcessMessages unless you know there are messages that your main thread needs to process that it wouldn’t otherwise process by itself. The application automatically processes messages when there’s nothing else to do, so if you have nothing to do, just let the application run itself.

–jeroen

Posted in .NET, C, C++, Delphi, Development, Software Development, Windows Development | Leave a Comment »

Counting bugs versus talking about them: a learning opportunity

Posted by jpluimers on 2021/07/07

Counting bugs (or issues for that matter) tells you exactly nothing. Numbers need context, so you need to discuss context. If there the number feels large, you do not even need an exact number: you already are in trouble.

More about this in this excellent twitter thread:

[WayBack] Thread by @michaelbolton: “1) Thinking about counting things to measure quality? You might be able to measure some things that bear on quality. By contrast, you ca […]”

  1. 1) Thinking about counting things to measure quality? You might be able to measure *some things* *that bear on* quality. By contrast, you can’t measure quality itself (as @jamesmarcusbach has said), but you can discuss it.Consider this: s/how many/let’s talk about each/g/
  2. When you suggest “let’s talk about each bug”, you might hear (or think) “No way! We have too many bugs to talk about each one! Let’s just count them instead!” If so, you can already infer some crucial things about the product and project, with no need to bother counting. /
  3. Of course, those inferences are only inferences, not facts. So investigate. When you do, you might be tempted to start counting bugs. But you’ll probably want to make sure that your count is appropriately accurate, precise, valid, reliable… So you need to examine each one. /
  4. Examining and evaluating each bug sounds like a pain. It is, to a degree. Few people like washing or repairing dirty linen in public. Yet a bug is not just a problem; it’s also an opportunity to learn some things. When you count instead of study, you lose that opportunity. /
  5. I love studying bugs. When I study bugs, I can become aware of certain things that go wrong, and some of those things get embedded into tacit knowledge. I can apply that knowledge, maybe consciously, maybe sub-, while testing, pairing with a developer, or coding myself. /
  6. In Rapid Software Testing, we suggest this: when someone asks for a number or a measurement, avoid misleading them by giving them a scalar. Consider offering a description, an assessment, a report, or a list. If you can describe and summarize, you might not NEED a number. /
  7. When you *are* offering a number, it had better be a valid number. When you count items, each item being counted had better be /commensurate/. That is, you must know the difference between “one of these” and “NOT one of these”. You must know how to count to one. /
  8. For a count to make sense, items must be commensurate—of describable size, weight, duration, significance, value, etc. etc., on a scale that people agree upon, accept, *and understand*. Otherwise communication will go pear-shaped in no time. /
  9. To go seriously about the business of getting a *valid* count, you’ll need to examine every bug. To do good analysis work, there’s no getting out of that. The same general principle applies to counting test cases, or “defect escapes”, or “invalid bug reports”. All of them. /
  10. “But management wants numbers!” I doubt that. Management almost certainly wants *to know things*—and from testers, knowledge about the status of the product and problems that threaten its value. Numbers might help to illustrate a story. They don’t, can’t TELL it. Words can. /
  11. Don’t be cowed into giving numbers without context. When asked for them, consider replying “misleading you is not a service that I offer,” and immediately offering a summarized, meaningful description of the state of factors that matter to people who are important. /
  12. All this applies to reports about the status or quality of the product, of the testing, of the project. And it applies to the work of individual testers, too. As an alternative to *measuring* something, analyze it, describe it, assess it, discuss it. Don’t just keep score. /
  13. What might we evaluate a tester’s work? Here’s an example set of elements of excellent testing:

    . It may not be complete, comprehensive, or tailored to your context. If it isn’t, revise it; fix it to fit. /

  14. Evaluating testers’ work? Go through the list and ask “are we happy with the tester’s work with respect to this element?” If Yes, great. If it’s outstanding, considering analyzing and then sharing that tester’s approaches with others; point out positive deviance from norms. /
  15. Unhappy with some element of the tester’s work? Talk about it. Discuss it. Maybe the tester needs to improve it through focus and deliberate practice; maybe the tester needs pairing and collaboration; or maybe others on the team can handle that element just fine. /
  16. As testers, we (supposedly) specialize in evaluating the quality of things via interaction, observation, experience with them. We consider quality criteria: capability, reliability, usability, charisma, security, scalability, compatibility, performance,… /
  17. People aren’t products, of course. And there are patterns common to evaluating the quality of anything: factors that make people happy or bring them value, or that in their absence trigger disappointment, loss, harm, or diminished value. But “Capability: 6” tells us little. /
  18. I was a program manager for a best-selling product. I would never have conceived of shipping a product (or not) by reading a scoring table. I didn’t care about metrics, test case counts, or bug counts. I needed relevant, concise stories about testing and bugs. /
  19. So: avoid agonizing about “measuring quality”. Consider instead learning to tell the product story, the testing story, and the quality-of-testing story. Talk about what’s OK, and move quickly to problem that threaten the product or project. [WayBack] developsense.com/blog/2018/02/h…
Postscript to this thread: in the middle of my writing it, the Twitter client on my iPad got into a state where it was accepting additions to the thread, but when it came time to send them out, the “Tweet All” button was greyed out. Anticipating a problem, I took screen shots. /

Predictably, the active “Cancel” button DID work, and the text was all lost. But, thanks to screen shots, for once I had a backup and was able to recover my work. It took time, but at least I could do it.

A user in this position doesn’t care about bug COUNTS. Only about the bug.

–jeroen

Read the rest of this entry »

Posted in Development, Software Development, Testing | Leave a Comment »

Diagrams om task states and transitions

Posted by jpluimers on 2021/07/06

For my link archive, a bunch of task state diagrams that include transitions between the states.

The diagrams are in no particular order.

–jeroen

Read the rest of this entry »

Posted in Development, Software Development | Leave a Comment »

Where my tweet about testing in production gained me knowledge about the Covid QR code systems

Posted by jpluimers on 2021/07/06

Even though RIVM twitter-care did not respond at all on my raised issue that the production environment leaded an acceptation environment URL, it did gain me some knowledge on their systems and the (then upcoming) European QR code systems.

[Archive.is] Jeroen Wiert Pluimers on Twitter: “Onhandig op de #CoronaCheck site van het @rivm de link hier (1) wijst nog naar de acceptatie omgeving en daar heb je authorisatie voor nodig. Zonder “.acc” werkt het ook niet: (2) Dit werkt wel: (3) CC @locuta… “

  1. web.acc.coronacheck.nl/nl/faq/1-6-welke-informatie-staat-in-mijn-qr-code/
  2. web.coronacheck.nl/nl/faq/1-6-welke-informatie-staat-in-mijn-qr-code/
  3. coronacheck.nl/nl/faq/1-6-welke-informatie-staat-in-mijn-qr-code/

The problem digging into it was that it only reproduces when inside the [Archive.is] Coronacheck Print Portaal after you have logged on via DigiD, so you cannot save it in the WayBack machine nor Archive.is.

This print portal isn’t a straightforward hierarchy of web-pages, but an actual Vue.js app that injects itself into [Wayback/Archive.is] nl-covid19-coronacheck-website/index.html at main · minvws/nl-covid19-coronacheck-website and dynamically changes the URL depending on the application state.

It also means that you cannot archive pages like coronacheck.nl/nl/print/vaccinatie-ophalen or coronacheck.nl/nl/print/keuze-papieren-bewijs as the Vue.js app will not understand state from those sub-URLs and go back to coronacheck.nl/nl/print/

The only other results of [Wayback] “acc.coronacheck.nl” – Google Search were:

Acceptance URLs in production

I had a hunch the CoronaCheck code would be open source, though finding it through the most obvious [Wayback] open source coronacheck app – Google Search failed. Since the web-site and app look very similar to the CoronaMelder web-site and app, I tried [Wayback] open source coronamelder app – Google Search and found the page with links: [Wayback] Colophon – Stop the spread of the coronavirus, download CoronaMelder.

Note that [Wayback] Open-Source Project Corona-Warn-App is a different beast. Though internationally available and released way earlier than the Dutch apps, the Dutch government has a huge ego (maybe even abbreviatable to Hugo) resulting in severe “not invented here” syndrome despite having had to be bailed out when “code black” happened in hospitals.

One thing that I learned is that there is one version of the code behind coronacheck.nl/nl/print/print-vaccinatie in the main branch of github.com/minvws/nl-covid19-coronacheck-website that has only acceptance URLs. They are in these locations:

Apparently, replacing these with production URLs is done during deployment, but I could not find the code that does it in the main repositories at [Wayback] github.com/minvws

European Corona/COVID-19 Green Pass QR certificate

One answer to my tweet was [Archive.is] Joel Haasnoot on Twitter: “gir.st/blog/greenpass.html… “ which provides more information on the European

These are the links I thought were interesting:

–jeroen

Read the rest of this entry »

Posted in Development, JavaScript/ECMAScript, Scripting, Software Development, Vue.js, Web Development | Leave a Comment »

SQL Server, [] brackets, keywords and special characters

Posted by jpluimers on 2021/07/06

A few links for my archive:

  • [WayBack] sql server – What is the use of the square brackets [] in sql statements? – Stack Overflow answer by Michael Haren:

    The brackets are required if you use keywords or special chars in the column names or identifiers. You could name a column [First Name] (with a space)–but then you’d need to use brackets every time you referred to that column.

    The newer tools add them everywhere just in case or for consistency.

     

  • [WayBack] tsql – What characters are valid in an SQL Server database name? – Stack Overflow answer by Scott Munro:

    Delimited names – surrounded by square brackets or double quotes (if QUOTED_IDENTIFIER is set to ON) – can contain basically anything other than the delimiters themselves. It is even possible to use the delimiters within the name with some escape logic. Note though that it is only the closing escape character that must be escaped. In the first example below, the single instance of the opening escape character in the name does not need to be escaped whereas the closing escape character does have to be escaped (by replacing the single instance with two). I guess the logic here is that whatever code that is parsing these statements is looking for a closing escape character and has is not interested in nested opening escape characters.

    • [Test[Test] -> Test[Test
    • [Test]]Test] -> Test]Test

    The following is a description of the rules surrounding non delimited (nonquoted) identifier names in SQL Server 2012. It is an extract from the document Guide to Migrating from MySQL to SQL Server 2012.

    Schema Object Names

    In SQL Server 2012, an object name can be up to 128 characters long.

    Nonquoted identifier names must follow these rules:

    • The first character must be alphanumeric, an underscore (_), an at sign (@), or a number sign (#).
    • Subsequent characters can include alphanumeric characters, an underscore, an at (@) sign, a number sign, or a dollar sign.
    • The identifier must not be a Transact-SQL reserved word. Guide to Migrating from MySQL to SQL Server 2012 8
    • Embedded spaces or special characters are not allowed.

    Identifiers that start with @ or a number sign have special meanings. Identifiers starting with @ are local variable names. Those that start with a number sign are temporary table names.

    To quote an identifier name in Transact-SQL, you must use square brackets ([]).

  • [WayBack] Database Identifiers – SQL Server | Microsoft Docs:
    1. Classes of Identifiers
    2. Rules for Regular Identifiers
    3. See Also

–jeroen

 

 

Posted in Database Development, Development, SQL, SQL Server | Leave a Comment »

Delphi: bumped into System.Classes.TLoginCredentialService while doing a “DefaultUsrPwDm” – Google Search

Posted by jpluimers on 2021/07/06

Doing a  “DefaultUsrPwDm” – Google Search, I bumped into the System.Classes.TLoginCredentialService class.

There is hardly any documentation.

It was introduced as [WayBack] System.Classes.TLoginCredentialService – XE2 API Documentation with the standard TObject template:

TObject is the ultimate ancestor of all objects and components.

System.Classes.TLoginCredentialService inherits from System.TObject. All content below this line refers to System.TObject.

TObject is the ultimate ancestor of all objects and components.

Although TObject is the based object of a component framework, not all objects are components. All component classes descend from TComponent.

Note: TObject is never directly instantiated. Although it does not use programming language features that prevent instantiation, TObject is an abstract class.

The documentation was updated in Delphi XE4 to [WayBack] System.Classes.TLoginCredentialService – RAD Studio API Documentation

TLoginCredentialService provides functionality for login action, regardless of framework.

TLoginCredentialService represents an extensible, framework agnostic, login credential service with support for callbacks (success, failure). It includes methods for:

  • Getting user credentials: DomainUsername and Password.
  • Registering and unregistering credentials from handlers.

See Also

That version also added [WayBack] System.Classes.ELoginCredendialError – RAD Studio API Documentation

ELoginCredendialError is the exception class for handling invalid login credentials.

ELoginCredendialError is raised when an application attempts to get specified, but unexisting, login credentials.

Nothing ever got added, no examples, no documentation, just look at for instance the Delphi Rio documentation:

Luckily, I found this for my research list (code at [WayBack] tlogincredentialservice.zip) : [WayBack] delphi – TLoginCredentialService usage example – Stack Overflow which uses globals, but that’s not the point of the demo (you can use different storage in your actual code)

I’ve just created a small demo of how to use it

Click here to download the code

In the following I’ll show some of the code:

First I need a record to hold Credentials, and a list of them :

Type
  TCredential = record
    Username, Password, Domain: string;
    constructor Create(const aUsername, aPassword, aDomain: string);
    function AreEqual(const aUsername, aPassword, aDomain: string): Boolean;
  end;

  TCredentialList = class(TList<TCredential>)
  public
    function IsValidCredential(const aUsername, aPassword, aDomain: string): Boolean;
  end;

then we need to define a context in wich we are calling this. Thats just a application unique string wich identifyes each Loginfunction

const
  Context = 'TForm1';

In Form create I create my list and add dummy data to it

procedure TForm1.FormCreate(Sender: TObject);
begin
  CredentialList := TCredentialList.Create;
  //Add Dummy data
  CredentialList.Add(TCredential.Create('AA', 'AA', 'DomainAA'));
  CredentialList.Add(TCredential.Create('BB', 'BB', 'DomainAA'));
  CredentialList.Add(TCredential.Create('CC', 'CC', 'DomainAA'));

  // Register your Login handler in a context.
  // This method is called when you try to login
  // by caling TLoginCredentialService.GetLoginCredentials();
  TLoginCredentialService.RegisterLoginHandler(Context, LoginCredentialEvent);
end;

I have placed a button on my form from wich I make my call to login :

procedure TForm1.Button1Click(Sender: TObject);
begin
  // The actual call to login
  // First param is the context
  // Second Parameres is a callback function given to the event handler.
  TLoginCredentialService.GetLoginCredentials(Context,
    function { LoginFunc } (const Username, Password, Domain: string): Boolean
    begin
      //The actual user validation
      Result := CredentialList.IsValidCredential(Username, Password, Domain);
    end);
end;

Finally I just need to implement my loginhandler:

//This is the "onLogin" event handler.
//This is called durring a login attempt
//The purpose of this event handler are to call tha callBack function with correct information
//and handle the result
procedure TForm1.LoginCredentialEvent(Sender: TObject; Callback: TLoginCredentialService.TLoginEvent; var Success: Boolean);
begin
  //Call the callback
  Callback(Sender, LabeledEdit1.Text, LabeledEdit2.Text, LabeledEdit3.Text, Success);

  //Handle the success.
  if Success then
    Label1.Caption := 'Yes'
  else
    Label1.Caption := 'No';
end;

Hope this answers the question.Dont forget to download the complete code here

–jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »