I override the function library kernel32.dll in Pascal and OpenProcess function returns 0. Function GetLastError() returns 87 error, that means
ERROR_INVALID_PARAMETER
87 (0x57)
The parameter is incorrect.
What could be wrong?
Program UODll;
const search_window = 'Ultima Online - xxx (The Abyss)';
function FindWindow(C1, C2: PChar): Longint; external 'FindWindowA#user32.dll stdcall';
function GetWindowThreadProcessId(hWnd: Longint; opt: Word): Word; external 'GetWindowThreadProcessId#user32.dll stdcall';
function OpenProcess(dwDesiredAccess: Word; inherit: Byte; pid: Word): Longint; external 'OpenProcess#kernel32.dll stdcall';
function GetProcessId(proc: Longint): Word; external 'GetProcessId#kernel32.dll stdcall';
function GetLastError(): Word; external 'GetLastError#kernel32.dll stdcall';
var
res, err: Word;
wnd, proc: Longint;
Begin
wnd := Findwindow('', search_window);
if (wnd > 0) then
begin
res := GetWindowThreadProcessId(wnd, res);
proc := OpenProcess($0400,0,res);
err := GetLastError();
writeln(IntToStr(proc));
writeln(IntToStr(err));
end;
End.
Im trying to use LongWord and Cardinal, but i have the same error.. Who can help me?)
P.S. its not delphi.. i dont know what is this :) Programm calls UOScript
OpenProcess has declaration
HANDLE WINAPI OpenProcess(
_In_ DWORD dwDesiredAccess,
_In_ BOOL bInheritHandle,
_In_ DWORD dwProcessId
);
dwDesiredAccess and pid are double words that are
typedef unsigned long DWORD;
i.e. 32bit on x86, according to this answer.
But Delphi/Pascal Word type is 16bit.
Also, BOOL is defined as
typedef int BOOL;
So, you should use Integer for inherit instead of Byte
So, your function declaration is incorrect.
Seems you should use Cardinal or LongWord instead of Word in your declarations.
If you use Delphi, you can import Windows module that has all Win API functions defined.
Related
Does anyone have experience with using the Winspool.EnumprinterData API in Delphi?
I found a demo for C++:
https://s-kita.hatenablog.com/entry/20120227/1330353801
I tried to covert it to Delphi as below:
procedure TForm1.GetPrinterData;
var
hPrinter : THandle;
pInfo: PPrinterInfo2;
bytesNeeded: DWORD;
dwRet : DWORD;
dwIndex: DWORD;
pValueName: PWideChar;
pTagName: PWideChar;
cbValueName: DWORD;
pcbValueName : DWORD;
pType: DWORD;
pData: PByte;
cbData: DWORD;
pcbData: PDWORD;
i : Integer;
printername : String;
dwValueNameSize : DWORD;
dwDataSize : DWORD;
begin
hprinter := GetCurrentPrinterHandle;
dwRet := EnumPrinterDataw(hprinter,i,nil,0, pcbValueName,pType,nil,0,pcbData);
end;
Question 1: EnumPrinterDataW result is not the same, even if I chose the same printer, and it often raises an Access Violation error.
Question 2: the API has many pointer type variables, the next step should allocate memory to some variable, but I do not know how to do thqt. For example pData: PByte; Pdata = Allocmem(pcbData^); <==== this is difficult to me, Pdata is TByte, how to allocmem(pcbData^) is TPwidechar how to do this?
This has taken me 2 days to deal with, and it is still a mess !!!!
There are some mistakes in your code:
you are not checking if GetCurrentPrinterHandle() returns a valid printer handle.
you are not initializing your i variable. You need to pass a 0-based index to EnumPrinterData(), but the value of i is indeterminate.
you are not initializing your pcbData variable. EnumPrinterData() expects a pointer to a DWORD variable that will receive the size of the data written to the pData buffer (or the needed size of the pData buffer if pData is nil). But your pcbData is not pointing to a valid DWORD.
Try something more like this:
procedure TForm1.GetPrinterData;
var
hPrinter: THandle;
dwIndex,
dwRet,
dwType,
dwMaxValueNameSize,
dwMaxDataSize,
dwValueNameSize,
dwDataSize: DWORD;
pValueName,
lpData: array of Byte;
sValueName: UnicodeString; // or WideString in D2007 and earlier
begin
hPrinter := GetCurrentPrinterHandle;
if hPrinter = 0 then
Exit; // or raise an exception
try
dwIndex := 0;
dwRet = EnumPrinterData(hPrinter, dwIndex, nil, 0, dwMaxValueNameSize, dwType, nil, 0, #dwMaxDataSize);
if dwRet = ERROR_NO_MORE_ITEMS then
Exit
else if dwRet <> ERROR_SUCCESS then
RaiseLastOSError(dwRet);
SetLength(pValueName, dwMaxValueNameSize);
SetLength(pData, dwMaxDataSize);
repeat
dwValueNameSize := 0;
dwDataSize := 0;
dwRet = EnumPrinterData(hPrinter, dwIndex, PWideChar(pValueName), dwMaxValueNameSize, dwValueNameSize, dwType, PByte(pData), dwMaxDataSize, #dwDataSize);
if dwRet = ERROR_NO_MORE_ITEMS then
Exit
else if dwRet <> ERROR_SUCCESS then
RaiseLasstOSError(dwRet);
SetLength(sValueName, PWideChar(pValueName), (dwValueNameSize div SizeOf(WideChar)) - 1); // -1 for null terminator
// use dwType, sValueName, and pData up to dwDataSize bytes, as needed...
Inc(dwIndex);
until False;
finally
// only if GetCurrentPrinterHandle returns a handle that needs to be closed now...
ClosePrinter(hPrinter);
end;
end;
Thanks for your great great help!
But have more questions, need your help. (sorry, I'm not good at English)
Q1. in your answer :
SetLength(sValueName, PWideChar(pValueName), (dwValueNameSize div SizeOf(WideChar)) - 1); // -1 for null terminator
I dont understnt this SetLength format.....and complier raise an Error :
[DCC Error] Unit1.pas(111): E2008 Incompatible types
Q2. how to get value :
sValueName ----> ValueName : array of Byte, how to get string value form an array of Byte
sorry for my poor ability. I really do not get pointer type Data, need more study
https://docs.perl6.org/language/nativecall
"As you may have predicted by now, a NULL pointer
is represented by the type object of the struct type."
https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexw
C++
LSTATUS RegQueryValueExW(
HKEY hKey,
LPCWSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData
);
lpReserved
This parameter is reserved and must be NULL.
With "native", how do I satisfy the "NULL" requirement?
constant WCHAR := uint16;
constant DWORD := int32;
sub RegQueryValueExW( DWORD, WCHARS, DWORD, DWORD, DWORD is rw, DWORD is rw ) is native("Kernel32.dll") returns DWORD { * };
$RtnCode = RegQueryValueExW( $Handle, $lpValueName, int32, REG_DWORD, $lpData, $lpcbData );
"int32" returns:
Cannot unbox a type object (int32) to int in method
CALL-ME at C:\rakudo\share\perl6\sources \947BDAB9F96E0E5FCCB383124F9
23A6BF6F8D76B (NativeCall) line 587
Many thanks,
-T
To pass a pointer to a DWORD you can use a CArray[DWORD]. For example, here I created a test library libmylib.so with a foo() function taking DWORD * (aka int32_t *) argument:
#include <stdio.h>
#include <stdint.h>
void foo (int32_t *bar) {
if ( bar == NULL ) {
printf( "Got NULL pointer\n" );
}
else {
printf("Got bar: %d\n", bar[0]);
}
}
Then test a Raku interface to this library using:
use v6;
use NativeCall;
constant DWORD := int32;
sub foo(CArray[DWORD]) is native("./libmylib.so") { * };
my #bar := CArray[DWORD].new;
#bar[0] = 1;
foo(#bar);
foo(CArray[DWORD]); # <-- Use a type object to pass a NULL pointer
Output:
Got bar: 1
Got NULL pointer
JJ and Brad on the Perl6 mailing list were correct. For a NULL, just pass it a zero. I had a booboo somewhere else.
i plan to call c++ dll from autohotkey
but i couldn't make it work.
if anyone help me much appreciate
this is what i done and tried
and it return null
hModule := DllCall("LoadLibrary", "Str", "Captcha.dll", "Ptr")
CaptchaProc := DllCall("GetProcAddress", "Ptr", hModule, "AStr",
"CaptchaProc", "Ptr")
test := DllCall(CaptchaProc, "Str", "test.png", "Str*", out)
MsgBox, %out%
MsgBox, %test%
this is exposure part in captcha.dll
void CaptchaProc(char* path, char* output) {
Mat frame = imread(path), blob;
thanks!
I want to create a DLL written in ADA that can be called from C++ or from ADA. I've compiled the DLL, and it exports my functions as well as Init and Final.
I now would like to call this DLL from Ada, using dynamic linking. The first half in the code below calls a C++ dll (without Init and Final). This works well. The second half tries to run Init before calling the DLL's function. But the line identified with lots of asterisks won't compile, instead I get error: missing operand.
Where am I going wrong?
with Ada.Text_IO; use Ada.Text_IO;
with Interfaces; use Interfaces;
with Interfaces.C; use Interfaces.c;
with System; use System;
with Ada.Unchecked_Conversion;
procedure SmallCode is
-- Definitions for dynamic DLL interface
type HANDLE is new Unsigned_32;
function LoadLibrary (lpFileName : char_array) return HANDLE;
pragma Import (stdcall, LoadLibrary, "LoadLibrary", "_LoadLibraryA#4"); -- Ada95 doesn't use #n
function GetProcAddress (hModule : HANDLE; lpProcName : char_array) return Address;
pragma Import (stdcall, GetProcAddress, "GetProcAddress", "_GetProcAddress");
--
-- The interface of the function we want to call. It is a pointer (access type) because
-- we will link it dynamically. The function is from AdaCallable.dll
type fnAdaCallable is access function(val : Integer_32) return Integer_32;
pragma Convention (Stdcall, fnAdaCallable);
function To_fnAdaCallable is new Ada.Unchecked_Conversion (Address, fnAdaCallable);
Pointer : Address;
function To_AdaCallable is new Ada.Unchecked_Conversion (Address, fnAdaCallable);
Pointer2 : Address;
type fnInit is access procedure;
pragma Convention (Stdcall, fnInit);
function To_fnInit is new Ada.Unchecked_Conversion (Address, fnInit);
PointerInit : Address;
type fnFinal is access procedure;
pragma Convention (Stdcall, fnFinal);
function To_fnFinal is new Ada.Unchecked_Conversion (Address, fnFinal);
PointerFinal : Address;
Library : HANDLE;
begin
Library := LoadLibrary (To_C ("AdaCallable.dll"));
if Library /= 0 then
Pointer := GetProcAddress(Library, To_C("_fnAdaCallable#4"));
if Pointer /= Null_Address then
declare
result : Integer_32;
begin
result := To_fnAdaCallable(Pointer) (74);
Put_Line("Returned result is " & Integer_32'Image(result));
end;
else
Put_Line("GetProcAddress returned Null_Address");
end if;
else
Put_Line("LoadLibrary returned 0");
end if;
Library := LoadLibrary (To_C ("libDllBuiltFromAda.dll"));
if Library /= 0 then
PointerInit := GetProcAddress (Library, To_C ("DllBuiltFromAdainit"));
if Pointer /= Null_Address then
Put_Line("Calling Init");
To_fnInit (PointerInit); -- ****************************************
Put_Line("Returned from Init");
Pointer2 := GetProcAddress(Library, To_C("AdaCallable#4"));
if Pointer2 /= Null_Address then
declare
result : Integer_32;
begin
result := To_AdaCallable(Pointer2) (74);
Put_Line("Returned result is " & Integer_32'Image(result));
end;
else
Put_Line("GetProcAddress returned Null_Address");
end if;
PointerFinal := GetProcAddress (Library, To_C ("DllBuiltFromAdafinal"));
if Pointer /= Null_Address then
Put_Line("Calling Final");
To_fnFinal (PointerFinal);
Put_Line("Returned from Final");
else
Put_Line ("GetProcAddress for final returned Null_Address");
end if;
else
Put_Line ("GetProcAddress for Init returned Null_Address");
end if;
else
Put_Line("LoadLibrary returned 0");
end if;
Put_Line ("Hello, World!");
end SmallCode;
Given
type Proc_P is access procedure (X : Integer);
P : Proc_P;
you can write
P (42);
as a shorthand for
P.all (42);
but if there’s no argument list to trigger the shortcut you have to be explicit: given
type Parameterless_Proc_P is access procedure;
Q : Parameterless_Proc_P;
you have to call the procedure by writing
Q.all;
By the way, in the line two before your asterisked line, I think you mean PointerInit.
I'm using the excellent Inno Setup installer and I notice that some Applications (often from Microsoft) get installed with their launch icon already highly visible ('pinned?') in the start menu (in Windows 7). Am I totally reliant on the most-recently-used algorithm for my icon to be 'large' in the start menu, or is there a way of promoting my application from the installer please?
It is possible to pin programs, but not officially. Based on a code posted in this thread (which uses the same way as described in the article linked by #Mark Redman) I wrote the following:
[Code]
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
const
// these constants are not defined in Windows
SHELL32_STRING_ID_PIN_TO_TASKBAR = 5386;
SHELL32_STRING_ID_PIN_TO_STARTMENU = 5381;
SHELL32_STRING_ID_UNPIN_FROM_TASKBAR = 5387;
SHELL32_STRING_ID_UNPIN_FROM_STARTMENU = 5382;
type
HINSTANCE = THandle;
HMODULE = HINSTANCE;
TPinDest = (
pdTaskbar,
pdStartMenu
);
function LoadLibrary(lpFileName: string): HMODULE;
external 'LoadLibrary{#AW}#kernel32.dll stdcall';
function FreeLibrary(hModule: HMODULE): BOOL;
external 'FreeLibrary#kernel32.dll stdcall';
function LoadString(hInstance: HINSTANCE; uID: UINT;
lpBuffer: string; nBufferMax: Integer): Integer;
external 'LoadString{#AW}#user32.dll stdcall';
function TryGetVerbName(ID: UINT; out VerbName: string): Boolean;
var
Buffer: string;
BufLen: Integer;
Handle: HMODULE;
begin
Result := False;
Handle := LoadLibrary(ExpandConstant('{sys}\Shell32.dll'));
if Handle <> 0 then
try
SetLength(Buffer, 255);
BufLen := LoadString(Handle, ID, Buffer, Length(Buffer));
if BufLen <> 0 then
begin
Result := True;
VerbName := Copy(Buffer, 1, BufLen);
end;
finally
FreeLibrary(Handle);
end;
end;
function ExecVerb(const FileName, VerbName: string): Boolean;
var
I: Integer;
Shell: Variant;
Folder: Variant;
FolderItem: Variant;
begin
Result := False;
Shell := CreateOleObject('Shell.Application');
Folder := Shell.NameSpace(ExtractFilePath(FileName));
FolderItem := Folder.ParseName(ExtractFileName(FileName));
for I := 1 to FolderItem.Verbs.Count do
begin
if FolderItem.Verbs.Item(I).Name = VerbName then
begin
FolderItem.Verbs.Item(I).DoIt;
Result := True;
Exit;
end;
end;
end;
function PinAppTo(const FileName: string; PinDest: TPinDest): Boolean;
var
ResStrID: UINT;
VerbName: string;
begin
case PinDest of
pdTaskbar: ResStrID := SHELL32_STRING_ID_PIN_TO_TASKBAR;
pdStartMenu: ResStrID := SHELL32_STRING_ID_PIN_TO_STARTMENU;
end;
Result := TryGetVerbName(ResStrID, VerbName) and ExecVerb(FileName, VerbName);
end;
function UnpinAppFrom(const FileName: string; PinDest: TPinDest): Boolean;
var
ResStrID: UINT;
VerbName: string;
begin
case PinDest of
pdTaskbar: ResStrID := SHELL32_STRING_ID_UNPIN_FROM_TASKBAR;
pdStartMenu: ResStrID := SHELL32_STRING_ID_UNPIN_FROM_STARTMENU;
end;
Result := TryGetVerbName(ResStrID, VerbName) and ExecVerb(FileName, VerbName);
end;
The above code first reads the caption of the menu item for pinning or unpinning applications from the string table of the Shell32.dll library. Then connects to the Windows Shell, and for the target app. path creates the Folder object, then obtains the FolderItem object and on this object iterates all the available verbs and checks if their name matches to the one read from the Shell32.dll library string table. If so, it invokes the verb item action by calling the DoIt method and exits the iteration.
Here is a possible usage of the above code, for pinning:
if PinAppTo(ExpandConstant('{sys}\calc.exe'), pdTaskbar) then
MsgBox('Calc has been pinned to the taskbar.', mbInformation, MB_OK);
if PinAppTo(ExpandConstant('{sys}\calc.exe'), pdStartMenu) then
MsgBox('Calc has been pinned to the start menu.', mbInformation, MB_OK);
And for unpinning:
if UnpinAppFrom(ExpandConstant('{sys}\calc.exe'), pdTaskbar) then
MsgBox('Calc is not pinned to the taskbar anymore.', mbInformation, MB_OK);
if UnpinAppFrom(ExpandConstant('{sys}\calc.exe'), pdStartMenu) then
MsgBox('Calc is not pinned to the start menu anymore.', mbInformation, MB_OK);
Please note that even though this code works on Windows 7 (and taskbar pinning also on Windows 8.1 where I've tested it), it is really hacky way, since there is no official way to programatically pin programs to taskbar, nor start menu. That's what the users should do by their own choice.
There's a reason there's no programmatic way to pin things to the taskbar/start menu. In my experience, I have seen the start menu highlight newly-created shortcuts, and that's designed to handle exactly this situation. When you see a newly-installed program show up on the start menu, it's probably because of that algorithm and not because the installer placed it there.
That said, if a new shortcut does not appear highlighted, it may be because the installer extracts a pre-existing shortcut and preserves an old timestamp on it, rather than using the API function to create a shortcut in the start menu.
Have a look at: http://blogs.technet.com/deploymentguys/archive/2009/04/08/pin-items-to-the-start-menu-or-windows-7-taskbar-via-script.aspx