Need help calling a proprietary C DLL from Python

D

Dennis Lee Bieber

And this is what I got:
VmxGet test - looking for valid record...
Before - PriKey = 0x0044F56C, SecKey = 0x0044F534
ci_PriKey = 0x0044F56C, ci_SecKey = 0x0044F534
After - PriKey = 0x0044F56C, SecKey = 0x0044F534
ci_PriKey = 0x0043D49C, ci_SecKey = 0x0043D484

So VmxGet() DID allocate new BSTR structures.

It might be interesting to extract the length data that is part of
the BSTR and compare.

ctypes.string_at(PriKey - 4, 4) #if I recall the arguments
vs
ctypes.string_at(ci_PriKey - 4, 4)

If the second (after conversion to integer) is larger than the
former, it could mean that the routine checks what is passed in to
ensure enough storage space, and if it won't fit, does the allocation.

If it were always going to do an allocation, there would have been
no excuse for /reading/ the passed in structure length.
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
C

Craig

So VmxGet() DID allocate new BSTR structures.

It might be interesting to extract the length data that is part of
the BSTR and compare.

ctypes.string_at(PriKey - 4, 4) #if I recall the arguments
vs
ctypes.string_at(ci_PriKey - 4, 4)

If the second (after conversion to integer) is larger than the
former, it could mean that the routine checks what is passed in to
ensure enough storage space, and if it won't fit, does the allocation.

If it were always going to do an allocation, there would have been
no excuse for /reading/ the passed in structure length.
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/

I changed to the following to followup on the length data:
printf ("Before - PriKey = 0x%8.8X, SecKey = 0x%8.8X\n", PriKey,
SecKey)
printf (" ci_PriKey = 0x%8.8X, ci_SecKey = 0x%8.8X\n",
ci_PriKey.value, ci_SecKey.value)
res = VmxGet( byref(hwmcb), byref(SecIndex), byref(Option),
byref(c_void_p(SrchKey)), byref(ci_SecKey), byref(ci_PriKey),
TypeDef )
printf ("After - PriKey = 0x%8.8X, SecKey = 0x%8.8X\n", PriKey,
SecKey)
printf (" ci_PriKey = 0x%8.8X, ci_SecKey = 0x%8.8X\n",
ci_PriKey.value, ci_SecKey.value)
print ord(string_at(PriKey - 4, 1)), ord(string_at(PriKey - 3, 1)),
ord(string_at(PriKey - 2, 1)), ord(string_at(PriKey - 1, 1))
print ord(string_at(ci_PriKey.value - 4, 1)),
ord(string_at(ci_PriKey.value - 3, 1)), ord(string_at(ci_PriKey.value
- 2, 1)), ord(string_at(ci_PriKey.value - 1, 1))
And, got:
Before - PriKey = 0x0028B6FC, SecKey = 0x0028B6C4
ci_PriKey = 0x0028B6FC, ci_SecKey = 0x0028B6C4
After - PriKey = 0x0028B6FC, SecKey = 0x0028B6C4
ci_PriKey = 0x0027D284, ci_SecKey = 0x0027D26C
41 0 0 0
7 0 0 0
Which makes sense for two reasons:
1. It would only return the non-space-filled part of the returned key.
2. At least from VB6, the variable does not even have to be used
before the call.

I have gone on to design a function for printing the contents as
fields in a Structure.
def DCOD_Print():
temp = unpack(DecoderRecordFormat, TypeDef.raw)
DCOD = DecoderRecord(temp[0], temp[1], temp[2], temp[3], temp[4],
temp[5])
print " DistID = \x22%s\x22" % DCOD.DistID
print " YearCode = \x22%s\x22" % DCOD.YearCode
print " AccountType = \x22%s\x22" % DCOD.AccountType
print "AccountNumber = \x22%s\x22" % DCOD.AccountNumber
print " Description = \x22%s\x22" % DCOD.Description
print " Unused = \x22%s\x22" % DCOD.Unused
return

class DecoderRecord(Structure):
_fields_ = [
("DistID", c_char_p),
("YearCode", c_char_p),
("AccountType", c_char),
("AccountNumber", c_char_p),
("Description", c_char_p),
("Unused", c_char_p)
]
DecoderRecordFormat = "3s4ss32s32s56s"

Then, a simple:
print DCOD_Print()
parses the record into its fields, and displays those fields.

In other files, some of those fields are VB6 currency types, which
have been described as 8-byte integers with an implied 4 decimal
places (which I guess would be __int64 or c_longlong and then divide
by 10,000, or simply put a decimal point 4 away from the end).

Any ideas on how best to process this type of data in Python?
 
D

Dennis Lee Bieber

41 0 0 0
7 0 0 0
Which makes sense for two reasons:
1. It would only return the non-space-filled part of the returned key.
2. At least from VB6, the variable does not even have to be used
before the call.
Hmmm... I wonder what the library would have done if you just passed
a 0 to it... Rather than even doing that SysAlloc...() mess...

PriKey = ctypes.int32(0) #or whatever the syntax was

... byref(PriKey)

May with an effective null pointer the library would just allocate
directly rather than trying to determine the length field of the one
passed in.

Something for the future, maybe...

print " DistID = \x22%s\x22" % DCOD.DistID

You realize you can avoid those \x22 literals by changing the outer
quotes?

print ' DistID = "%s" ' % ....

or using triples

print """ DistID = "%s" """ % ...
In other files, some of those fields are VB6 currency types, which
have been described as 8-byte integers with an implied 4 decimal
places (which I guess would be __int64 or c_longlong and then divide
by 10,000, or simply put a decimal point 4 away from the end).

Don't divide directly; you might lose significance as the result is
converted to double-precision float.

You could possibly convert to string, splice in that . and then pass
the result to the Decimal module/type...
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
C

Craig

Hmmm... I wonder what the library would have done if you just passed
a 0 to it... Rather than even doing that SysAlloc...() mess...

PriKey = ctypes.int32(0) #or whatever the syntax was

... byref(PriKey)

May with an effective null pointer the library would just allocate
directly rather than trying to determine the length field of the one
passed in.

Something for the future, maybe...


You realize you can avoid those \x22 literals by changing the outer
quotes?

print ' DistID = "%s" ' % ....

or using triples

print """ DistID = "%s" """ % ...




Don't divide directly; you might lose significance as the result is
converted to double-precision float.

You could possibly convert to string, splice in that . and then pass
the result to the Decimal module/type...
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/


I made these changes:
# SecKey =
windll.oleaut32.SysAllocStringByteLen("1234567890123456789012345678901234567890\x00",
41)
SecKey = c_int32(0)
ci_SecKey = c_int32(SecKey)
# PriKey =
windll.oleaut32.SysAllocStringByteLen("ABCDEFGHIJKLMNOPQRSTUVWXYZ12345678901234\x00",
41)
PriKey = c_int32(0)
ci_PriKey = c_int32(PriKey)
And got:
Traceback (most recent call last):
File "C:\temp\vbisam_test_2.py", line 123, in <module>
ci_SecKey = c_int32(SecKey)
TypeError: an integer is required

Creating 2 "dummy" BSTR's isn't too bad of an option anyway.

No, being somewhat new I didn't realize I could use (') in place if
(") if I wanted to use a (") as a literal, but it seems to make a lot
of sense now. I don't understand why I never tried it.

As for the division vs. string manipulation, I agree - the string
seems to be the simplest way to insure no loss of data.

Thanks for all the input.
 
D

Dennis Lee Bieber

SecKey = c_int32(0)
ci_SecKey = c_int32(SecKey)
# PriKey =
windll.oleaut32.SysAllocStringByteLen("ABCDEFGHIJKLMNOPQRSTUVWXYZ12345678901234\x00",
41)
PriKey = c_int32(0)
ci_PriKey = c_int32(PriKey)

Only one call needed... Since the attempt was to pass a null pointer
you only need a single c_int32() for each (pri/sec) pair.

PriKey = c_int32(0)
SecKey = c_int32(0)
.... dll-call(.... byref(PriKey), byref(SecKey)...) #or whatever the
order was
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top