title: Delphi DLL not unloading, probably due to still-allocated GDI
body: <p>We wrote a DLL to perform all of our printing functions. It allows us to do print previews, printing, and also generate PDFs.</p>
  
  <p>We now have a particular pattern of use of this DLL, after which the DLL fails to unload properly. The consequence is that when we exit the main program, it disappears but does not terminate, and we have to kill the process manually.</p>
  
  <p>I imagine that the culprit is that some GDI resources are not being properly "closed" (and when I say this, I say it from great depths of ignorance with regard to GDI). We do not handle the GDI resources directly, but rather the GDI resources are employed for us when we use various Delphi components.</p>
  
  <p>Any hints as to how to find and fix such a problem? We used GDIView to confirm that some GID resources remain after we attempt to terminate the program, but I have no idea how to associate those Windows/Kernel handles with the underlying Delphi code.  I can supply GIDView listings at various times during the execution of the program.</p>
  
  <p>Thanks!</p>
  
  <p>Jon (Delphi 2007)</p>
  
  <hr>
  
  <p>I responded to the suggestions that were made, but no one responded to my responses. Eventually, I gave up.  I ended up writing a suicide routine that not only kills my own process, but also every other process with the same name, as a way around the problem. Ridiculous overkill, but I seemed to have no other choice.  I'm using a freeware ProcessInfo facility I found somewhere.</p>
  
  <pre><code>procedure KillNamedProcesses(pName : String);
  // used to clean up programs that hang as a result of DLLs not unloading
     var
        ProcessInfo : TProcessInfo;
        ProcessName : String;
        i : INTEGER;
        currentPID : cardinal;
     BEGIN
     currentPID := GetCurrentProcessID;
     pName := UpperCase(pName);
     ProcessInfo := TProcessInfo.Create(nil);
  
     // kill all old processes (not our process)
     for i := 0 to ProcessInfo.RunningProcesses.Count - 1 do begin
        ProcessName := ProcessInfo.RunningProcesses[i].ExeFile;
        IF (UpperCase(ProcessName) &lt;&gt; pName) THEN CONTINUE;
        IF (currentPID &lt;&gt; ProcessInfo.RunningProcesses[i].ProcessID) then
           ProcessInfo.RunningProcesses[i].TerminateProcess;
        END;
     // kill the last one (ourselves)
     for i := 0 to ProcessInfo.RunningProcesses.Count - 1 do begin
        ProcessName := ProcessInfo.RunningProcesses[i].ExeFile;
        IF (UpperCase(ProcessName) &lt;&gt; pName) THEN CONTINUE;
        ProcessInfo.RunningProcesses[i].TerminateProcess;
        END;
     ProcessInfo.Free;
     END; // KillNamedProcess
  </code></pre>