How can I enum RT_VERSION resource languages? - windows

I am currently trying to enum all resource languages from the RT_VERSION resourcetype.
This is what I have so far with no luck, since my callback procedure doesn't fire at all.
function TEnumResLangProc (hModule: HMODULE; lpszType, lpszName : PChar; wIDLanguage : Word; lParam : Longint) : Bool; stdcall;
begin
MessageBox(0, lpszName, '', 0); // For testing
MessageBox(0, lpszType, '', 0); // For testing
result := true;
end;
if not EnumResourceLanguages (HINSTANCE, RT_VERSION, PChar('1'), #TEnumResLangProc, 0)
then RaiseLastOSError;
I always get the errorcode 1813 and I couldn't find any documentation about it. I'm also not sure about the "Index" Paramater PChar('1') What do I do wrong and how can I enum all RT_VERSION languages?
Edit:
The value 1031 is wanted

This error code is ERROR_RESOURCE_TYPE_NOT_FOUND. It means that there are no resources of that type and name in the specified module.
The specified resource type cannot be found in the image file.
Note that the error codes are documented: http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381.aspx
Quite likely the name is wrong. Did you mean to pass MakeIntResource(1) or '#1'?
Your callback function should set the return value. The compiler will warn you of that mistake. You really should enable and heed warnings. Also, the type declarations are not 64 bit compatible, but I doubt that matters here.

Related

Delphi: how can i get list of running applications with starting path?

Using Delphi (windows app) i want to get list of other applications running currently. Here How to check if a process is running using Delphi? i've found great tutorial about geting filenames/names of running application, however it gives names only process name (for example NOTEPAD.EXE). I've used naturally part with
UpperCase(ExtractFileName(FProcessEntry32.szExeFile))
and
UpperCase(ExtractFilePath(FProcessEntry32.szExeFile))
and just
UpperCase(FProcessEntry32.szExeFile)
but obviously FProcessEntry32.szExeFile does not have a path to file/process
Is there a simply way of getting list with paths? Here's How to get the list of running processes including full file path? solution with JclSysInfo library, but i cant use it in place of work in project.
I looked at what I could in Google and what I found usually concerned just the application that is running or the application that is active, but I can't just find a list of all running applications. Maybe i'm missing something obvious?
I'm not looking for any complex procedures, I'm not much interested in process parrent, or if there is no access to the process path, I don't have it and don't bother.
Any simple hint?
OK, due to helpfull comment from #TLama i've combined topics above to take name and path of process:
function processExists(exeFileName: string): Boolean;
var
ContinueLoopP, ContinueLoopM: BOOL;
FSnapshotHandle1, FSnapshotHandle2: THandle;
FProcessEntry32: TProcessEntry32;
FMODULEENTRY32: TMODULEENTRY32;
begin
FSnapshotHandle1 := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
FMODULEENTRY32.dwSize := SizeOf(FMODULEENTRY32);
ContinueLoopP := Process32First(FSnapshotHandle1, FProcessEntry32);
ContinueLoopM := Module32First(FSnapshotHandle2, FMODULEENTRY32);
Result := False;
while Integer(ContinueLoopP) <> 0 do
begin
if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
UpperCase(ExeFileName)) or (UpperCase(FProcessEntry32.szExeFile) =
UpperCase(ExeFileName))) then
Result := True;
ShowMessage(FMODULEENTRY32.szExePath + FProcessEntry32.szExeFile);
ContinueLoopP := Process32Next(FSnapshotHandle1, FProcessEntry32);
ContinueLoopM := Module32Next(FSnapshotHandle2, FMODULEENTRY32);
end;
CloseHandle(FSnapshotHandle1);
CloseHandle(FSnapshotHandle2);
end;
But still FProcessEntry32.szExeFile returns empty string. What i'm doing wrong? Thank You in advance.
I cannot write comment (low score), so I need to write as "answer". Try this code,
using FProcessEntry32.th32ProcessID as parameter:
Function QueryFullProcessImageNameW(hProcess:THandle; dwFlags:Cardinal; lpExeName:PWideChar; Var lpdwSize:Cardinal) : Boolean; StdCall; External 'Kernel32.dll' Name 'QueryFullProcessImageNameW';
Function GetFullPath(Pid:Cardinal) : UnicodeString;
Var rLength:Cardinal;
Handle:THandle;
Begin Result:='';
Handle:=OpenProcess(PROCESS_QUERY_INFORMATION, False, Pid);
If Handle = INVALID_HANDLE_VALUE Then Exit;
rLength:=256; // allocation buffer
SetLength(Result, rLength+1); // for trailing space
If Not QueryFullProcessImageNameW(Handle, 0, #Result[1],rLength) Then Result:='' Else SetLength(Result, rLength);
End;
This is a simple way I think. If you want to get the loaded DLL's full name, use
FMODULEENTRY32.hModule with GetModuleFileNameW function.

Why doesn't calling a function with identical signatures in different units result in compiler error?

Why doesn't this code result in a compiler error? I would have expected error for example 'ambiguous call to "CallMe"'. Is this a bug in the compiler or in the language? This can worked around by using the unit name and a dot in front of the function call but this not shield user code and library code against name collisions. You think that your code did something but it did something else and that's bad.
uses
Unit2, Unit3;
{$R *.lfm}
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(IntToStr(CallMe(5)));
end;
unit Unit2;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
function CallMe(A: Integer) : Integer;
implementation
function CallMe(A: Integer) : Integer;
begin
Result := A * 2;
end;
end.
unit Unit3;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
function CallMe(A: Integer) : Integer;
implementation
function CallMe(A: Integer) : Integer;
begin
Result := A * -1;
end;
end.
From documentation:
If two units declare a variable, constant, type, procedure, or function with the same name, the compiler uses the one from the unit listed last in the uses clause. (To access the identifier from the other unit, you would have to add a qualifier: UnitName.Identifier.)
As said it is by design, the compiler loads symbols from units using a stack based approach, and parses through the stack from last loaded to first loaded to search for a symbol. Preprocessor state is directly merged into the global state though.
Cross unit overloading is an exception though. If you mark both functions with overload; directive, you get an error (bla was the name of the function in the test)
[dcc32 Error] test.dpr: E2251 Ambiguous overloaded call to 'bla'
Unit1.pas(8): Related method: procedure bla;
Unit2.pas(8): Related method: procedure bla;
if you have two different signatures, it will select the best matching one.
cross overloading is a newer feature, but I don't remember exactly when. My guess is D2006.

CreateProcess hook to add CommandLine

I have a project that was adding some specific flags (command lines) to Chrome browser, the problem is that I was doing this by creating a new Chrome shortcut, with the flags I want to execute.
In the last days this solution became too superficial, and I was requested to do something more 'deeper'. Looking on Windows Registry, I didn't found any good solution to always add this flags when someone run Chrome, so I started thinking to hook CreateProcess into explorer, and check if the process that is about to run is Chrome, then I add the flags in the lpCommandLine attribute.
I know hook into explorer is a pretty 'intrusive' solution, but this became helpful because I have some other achieves I was putting off on this project, and hooking will help me to get all them done.
I got the hook working, I tried by many ways to add the command lines when chrome is found, but no success... Right now (and I tried at least 8 different solutions) my detour function is:
function InterceptCreateProcess(lpApplicationName: PChar;
lpCommandLine: PChar;
lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
bInheritHandles: BOOL;
dwCreationFlags: DWORD;
lpEnvironment: Pointer;
lpCurrentDirectory: PChar;
const lpStartupInfo: STARTUPINFO;
var lpProcessInformation: PROCESS_INFORMATION): BOOL; stdcall;
var
Cmd: string;
begin
Result:= CreateProcessNext(lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
if (POS(Chrome, UpperCase(String(lpApplicationName))) > 0) then
begin
Cmd:= ' --show-fps-counter';
lpCommandLine:= PChar(WideString(lpCommandLine + Cmd));
ShowMessage(lpCommandLine);
end;
end;
The "--show-fps-counter" is the command line I'm trying to add without success.
My Delphi version is XE4.
Ok, this is a pretty obvious thing... I need to add the parameter BEFORE calling the CreateProcessNext (original function)!
So, simply doing:
if (POS(Chrome, UpperCase(String(lpApplicationName))) > 0) then
begin
lpCommandLine:= PChar(lpCommandLine + ' --show-fps-counter');
end;
Result:= CreateProcessNext(lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
works... note that I just inverted the order to change the lpCommandLine. Thank's for all participants and I'll still consider what was said here.

OEMToCharW returns wrong characters

I read the input buffer from a console application (CMD) like this:
var
pBuffer : array [0..2400] of Widechar;
dBuffer : array [0..2400] of WideChar;
CReadBuffer : Cardinal;
BytesRead : Cardinal;
begin
// ....
ReadFile(BuffHandle, pBuffer[0], CReadBuffer, BytesRead, nil);
pBuffer[BytesRead] := #0; // Finish/End the WideString
OemToCharW(pBuffer, dBuffer);
MessageBoxW (0, dBuffer, '', 0);
// ....
end;
For some reason I get weird chars...
CMD should have the oem charset. I used OEMtoCharA before and it worked fine.
What do I do wrong?
Thanks for help.
EDIT:
I use Delphi7
As you said, CMD has the OEM charset, which means the pBuffer should be declared as
pBuffer: array[0..2400] of AnsiChar;
Now try again (can't check this right now myself).
It transpires that the declaration of OemToCharW is incorrect in Delphi 7. In Delphi 7 the first parameter is incorrectly declared as PWideChar when it should be PAnsiChar. You should redeclare OemToCharW correctly in your code and possibly consider using OemToCharBuffW instead.

Is it possible to debug a COM dll in VS2008?

This may be a very stupid question.
Is it possible to debug a COM dll in VS2008 for which I do not have the source code?
The reason I want to do this is I am passing an Array to a COM method and I expect this Array to be populated by the method.
However the Array is not being populated. So I want to step into the COM method to see whats happening. is this possible?
Below is an example of the code I am using:
Array binaryArray = Array.CreateInstance(typeof(sbyte), 896);
bool success = photo.GetBinaryData(binaryArray);
IDL for the GetBinaryData method:
[id(0x000000c9)]
HRESULT GetBinaryData(
[in] SAFEARRAY(char) buffer,
[out, retval] VARIANT_BOOL* retval);
The GetBinaryData method is the COM method which I would like to step into.
EDIT: Adding a Delphi test script which works
procedure TComTestForm.TestUserBtnClick(Sender: TObject);
var
nCnt :integer;
User :IUser;
Persona :IUserPersona;
ArrayBounds :TSafeArrayBound;
ArrayData :Pointer;
TagList :PSafeArray;
nSize :integer;
begin
User := Session.GetUser;
ArrayBounds.lLbound := 0;
ArrayBounds.cElements := 0;
TagList := SafeArrayCreate( varInteger, 1, ArrayBounds );
User.GetTags( TagList );
if SafeArrayAccessData( TagList, ArrayData ) = S_OK then
begin
nSize := TagList.rgsabound[0].cElements;
OutLine( '----Available Tags, ' + IntToStr(nSize) + ' tags' );
for nCnt := 0 to nSize - 1 do
begin
OutLine( IntToStr( IntegerArray(ArrayData)[nCnt] ) );
end;
OutLine( '----');
SafeArrayUnAccessData( TagList );
SafeArrayDestroy( TagList );
end;
end;
In principle, yes, you can step through the code of the COM method implementation instruction-by-instruction.
However, even if you know assembly well and understand exactly how all the processor instructions work, it's a tall order to debug someone else's code in this fashion unless it's a really, really simple method.
If you are new to assembler, don't even consider it unless you're prepared to do weeks of learning curve first.
If the COM method doesn't appear to be working in the way you expected based on its documentation, I would first try to test the method using unmanaged code (e.g. C++), as your problem may be in the COM Interop marshalling rather than in the COM method itself.

Resources