Archive: Pocket PC .netCF and registry and installing CAB files


Pocket PC .netCF and registry and installing CAB files
Hi i am having lots of trouble understanding the few elements i need to use in NSIS, i am newb ofcourse.
I want to check on the connected pocket pc, what version of .net compact framework it has. If it needs .netcf installed, it will grab the appropriate CAB package to install it. I have NETCFv2.ppc.armv4.cab and NETCFv2.ppc.armv4i.cab not sure if these are the appropriate packages.
I am not sure how to use the ppc-registry plugin to search for the version of .netcf installed and then select the right cab.

And how do I select the right CAB file for my app to install?
Basically, I have my CAB files for the App i wish to install (ARMV4, MIPS and SH3), so i assume i have to find the OS i'm installing to, then select the appropriate package, so similar to what i have to do with .netcf. And I also have been getting the error that my CAB file is not a valid setup file. but this may be because i'm trying to install the wrong cab file.

I have had quite an extensive look through wiki and examples without much luck.
thanks for any help


To find out the processor of the device, you can use the following:

!include LogicLib.nsh

!define PROCESSOR_ARCHITECTURE_INTEL 0
!define PROCESSOR_ARCHITECTURE_MIPS 1
!define PROCESSOR_ARCHITECTURE_SHX 4
!define PROCESSOR_ARCHITECTURE_ARM 5


System::Alloc 40
Pop $0
System::Call "CeGetSystemInfo(i r0)"
System::Call "*$0(i, &i2 .r1)"
System::Free $0

${Switch} $1
${Case} ${PROCESSOR_ARCHITECTURE_INTEL}
DetailPrint "intel processor"
${Break}
${Case} ${PROCESSOR_ARCHITECTURE_ARM}
DetailPrint "arm processor"
${Break}
${Case} ${PROCESSOR_ARCHITECTURE_SHX}
DetailPrint "shx processor"
${Break}
${Case} ${PROCESSOR_ARCHITECTURE_MIPS}
DetailPrint "mips processor"
${Break}
${Default}
DetailPrint "unknown processor"
${Break}
${EndSwitch}
You might be able to do the same using the registry plug-in, but calling a defined API is always better.

hi kichik, thanks for ur speedy replies.
i tried just copying and pasting your code, i get an illegal operation when the script gets to it when executing.

i can attach a copy of my script if you would like to look at that.
thanks again


Did you add a call to CeRapiInit? I have added a complete should-be-working example to the wiki.


I think i am calling it.. but with my skill level i dont think i would know if i weren't

in this i have all the cab files trying to install, just not sure how to go about finding the processor type then selecting the right file that way, i have attached the script

thanks


The code seems right to me. Maybe the double CeRapiInit bothers it... Try removing the PPC-Registry calls, you don't use it anyway. If it still crashes, add some message boxes between the calls to see exactly where it crashes.


Can i ask what environment you develop in??

would this affect the operation of the script?
I tried taking out the ppc-registry calls with no change in the result


do you know of any more examples or explainations of how to use this feature?


I haven't tested this script as I don't have an environment to develop PDA applications. I don't own a Pocket PC/SmartPhone/PDA.

What about the message boxes?


yeah sorry i haven't tried the messageboxes yet, will get back to you on monday when back at work, thanks for your help


hi, using msg boxes, i found that its having the error on this line:


System::Call "CeGetSystemInfo(i r0)"


i'm still not too sure what "i" and "r0" represent.

n00b factor,
thanks

Kickik and zbd, the code is lacking "rapi::" before the function "CeGetSystemInfo". It should be:

System::Call "rapi::CeGetSystemInfo(i r0)"


This should solve it. I also fixed the wiki page relating to this topic.

EDIT:
i'm still not too sure what "i" and "r0" represent.
The "i" in the line above mentioned indicates that the parameter is a "pointer to memory" to the one allocated right before (general definition for "i" is "integer", but in this case, the integer is the memory location). The "r0" indicates that the value is the value of the variable "$0" in NSIS.

fantastic, thank you, that was exactly it.
thanks for all help, no doubt i will be back for more brain picking :D


Hi I'm also a newb and trying to do almost the exact same thing, find the version of .netcf and update it if necessary. But it seems like so far this thread focused on your 2nd issue of finding the OS on the device and the right CAB for it.

Here's an excerpt from a link I found on the microsoft.public.pocketpc.developer group, to a document for creating a .msi file.

Begin by connecting to the device using CeRapiInitEx.

Use CeFindAllFiles to search the device's Windows directory for GAC_mscorlib_*.dll. If that is present, some flavor of the .NET Compact Framework is installed on the device.

Query the device registry and enum the values in HKLM\SOFTWARE\Microsoft\.NETCompactFramework. You should find registry keys which represent the build of NETCF that is present. (e.g. 1.0.2268.00:REG_DWORD:0). This version is created by all .cab installs and is included on all future ROM installs. It was missing from the initial ROM install of the RTM .NET Compact Framework, so if you do not find it, assume the value is 1.0.2268.0.

At this point you should know whether the .NET Compact Framework is present, and whether you need to deploy your own version to the device. If you also need to deploy the SQL CE files, you can use a similar mechanism of searching the Windows directory for the GAC'd libraries. The SQL install does not post its version to the registry, so the only way to know the build version would be to read the Win32 resources of the .dll. In the sample I have opted to always install the SQL .cabs if they are required. This should be safe, because CE installer will prevent an inadvertent downgrade of the SQL packages on the device. A similar approach could be taken with the .NET Compact Framework as well.
Anyone know how to get rapi to do this? Or I guess it would be how to get NSIS to get rapi to do thi. I'm just learning what rapi is, what GAC is, etc.

Thanks

I'm not sure at all about this but the way i was trying to do it was with PPC-Registry plugin, i'm guessing that after .netCF v2 is installed, a network key is created somewhere, i guess i have to work out where it makes this key and how exactly to do identify that it exists, then install the appropriate CAB. This is what i have so far.


!include "PPC-Registry.nsh"
!include "LogicLib.nsh"

Section "registry"
; This opens the connection to the Pocket pc
; it returns 0 on success -1 on failure

${PPC-registry::CeRapiInit} $R0

; This requires the LogicLib plugin included

${If} $R0 = '-1'
MessageBox MB_OK 'Connection Failed'
${ElseIf} $R0 = '0'
MessageBox MB_OK 'Connection Success'
goto keyexist
${Else}
MessageBox MB_OK '$$R0 is "$R0"'
${EndIf}

keyexist:
...

This is where i'm not too sure what to use to search or how to use it ... :weird:

${PPC-registry::Open} "HKEY_LOCAL_MACHINE" "/K=0 /V=1 /S=0 /B=1 /N=" $0
StrCmp $0 0 0 loop
MessageBox MB_OK "Error" IDOK end

loop:
${PPC-registry::Find} "$0" $1 $2 $3 $4

; I dont know how to specify what to search for???

MessageBox MB_OKCANCEL '$$1 "path" =[$1]$\n\
$$2 "value" =[$2]$\n\
$$3 "string" =[$3]$\n\
$$4 "type" =[$4]$\n\
$\n\
Find next?' IDOK loop


${PPC-registry::CeRapiUninit}

or..

${PPC-registry::KeyExists} "HKEY_LOCAL_MACHINE\SOFTWARE\Zeb" $R0
; MessageBox MB_OK "PPC-registry::KeyExists$\n$\n\
; Errorlevel: [$R0]"
${If} $R0 = '-1'
MessageBox MB_OK "Key doesn't exist"
${Else}
MessageBox MB_OK 'Key Exists'
${EndIf}

if anyone can help with this, please do, thanks

Hmm... the plug-in lacks a function to enumerate the values in the registry key. CeRegEnumValue is the function that does this.

You could request the feature to be implemented by Instructor in the Registry plug-in thread here in the forums as he usually (if not always) announces new versions in their original threads, or maybe just wait for him here.


what about System::Call "rapi::CeRegEnumValue()"

i don't know if it even exists
and wouldn't ${PPC-registry::KeyExists} do almost the same thing?


I'm having a few problems (i think) with the detecting processor type.
I'm guessing that the vale $1 changes depending on what processor it is. I've tested on 3 devices, all return a value (4096) that is unknown by the example in the wiki. I'm pretty sure that they are all Intel processors. (Devices: i-Mate PDA-N, Dell Axim X51v, Garmin iQue M5)

So they all return a value that doesn't match any of the defined processor types. Does anyone know about this?

and what exactly is this line doing?


System::Call "*$0(i, &i2 .r1)"

Hmmm... The first value is an union, which is a value that is retrieved depending on the type passed. The second part of the union holds another structure, so parameter 1 here should be the structure, and parameter 2 is the "dwPageSize" (page size) which returns exacly 0x1000 = ${MEM_COMMIT}.

So, you need to create another structure, reference it in the first parameter, call the structure, and get the value of the first parameter of it ("wProcessorArchitecture"):

System::Alloc 40
Pop $0
System::Alloc 4
Pop $1
System::Call "rapi::CeGetSystemInfo(i r0)"
System::Call "*$0(i r1)"
System::Call "*$1(&i2 .r2, &i2)"

System::Free $1
System::Free $0


and $2 is the return value of the "wProcessorArchitecture" in this case. Hopefully this code won't give problems...

There's no union in SYSTEM_INFO. I can't get the Wiki page to load, but the problem, at least in your code so probably in mine as well, is again the missing "rapi::". There's no need for dereferencing $0, it's already a pointer directory to the SYSTEM_INFO structure.

zbd, add "rapi::" before CeGetSystemInfo, just deguix did with CeRapiInit.


Hmm... I edited the post so quickly you didn't notice I fixed it, even before you posted. =( This is all that I need to say:

MSDN link

typedef struct _SYSTEM_INFO {
union {
DWORD dwOemId;
struct {
WORD wProcessorArchitecture;
WORD wReserved;
};
};
DWORD dwPageSize;
LPVOID lpMinimumApplicationAddress;
LPVOID lpMaximumApplicationAddress;
DWORD_PTR dwActiveProcessorMask;
DWORD dwNumberOfProcessors;
DWORD dwProcessorType;
DWORD dwAllocationGranularity;
WORD wProcessorLevel;
WORD wProcessorRevision;
} SYSTEM_INFO;

That's very weird. MSDN for WinCE says there's no union there. It's possible they got it wrong.

In that case the following should line should be fixed.

System::Call "*$0(i, &i2 .r1)"
The first parameter ("i, ") should be removed.
System::Call "*$0(&i2 .r1)"
That change should be made to the original code, not deguix's code.

Btw... woulnd't that be getting a structure, or would it only be retrieving the first parameter of the structure as you specified the parameter's length?


It'd be getting the first parameter of the structures, regardless of the size specification. That's the syntax of structure manipulation.

*address(type in out, type in out, ...)
$0 is already the pointer to the structure. There's no need to another pointer to it.

No, I mean, there's this structure inside the SYSTEM_INFO structure:

    struct {
WORD wProcessorArchitecture;
WORD wReserved;
};


Isn't the code aiming for "wProcessorArchitecture"? Wouldn't you need to allocate another structure to get the value for that parameter?

(EDIT: Well, now I see I need to put the line 'System::Call "*$0(i r1)""' in my code before the function call, because the memory address for this second struct would be an input parameter...)

No, it's not a pointer to a structure. In memory, the members are laid out one after the other. There's no pointer to another structure containing wProcessorArchitecture and wReserved. Also, because of the union, dwOemId and wProcessorArchitecture will have the same address.

You can see for yourself how it works with the following simple C program.

SYSTEM_INFORMATION si;
printf("si @ %d\n", &si);
printf("wProcessorArchitecture @ %d\n", &si.wProcessorArchitecture - &si);
printf("dwOemId @ %d\n", &si.dwOemId - &si);
printf("wReserved @ %d\n", &si.wReserved - &si);
printf("dwPageSize @ %d\n", &si.dwPageSize - &si);

aww... it's the structure itself, not a pointer... =(. *hides*


lol :confused:
u guys are getting a bit ahead of me i think.

i'm just not too sure if the values for the processor architecture are right, as in where i define the processor types


Function InstallCFCAB
;finds appropriate processor so we know what cab file to install

; known processor types
!define PROCESSOR_ARCHITECTURE_INTEL 0
!define PROCESSOR_ARCHITECTURE_MIPS 1
!define PROCESSOR_ARCHITECTURE_SHX 4
!define PROCESSOR_ARCHITECTURE_ARM 5
!define PROCESSOR_ARCHITECTURE_ARM4I 4096

System::Call "rapi::CeRapiInit() i .r0"

${If} $0 == 0 # S_OK
;MessageBox MB_OK "$0 is '$$0'"

; Get the System Info this contains the processor type
System::Alloc 40
Pop $0
System::Call "rapi::CeGetSystemInfo(i r0)"
System::Call "*$0(i, &i2 .r1)"
System::Free $0

; MessageBox MB_OK "'$$0' is $0"
; MessageBox MB_OK "'$$1' is $1"

; Now install the compact framework2.0 cab file
${Switch} $1

/* Not supporting this yet
${Case} ${PROCESSOR_ARCHITECTURE_INTEL}
${Break}
*/

${Case} ${PROCESSOR_ARCHITECTURE_ARM}
MessageBox MB_OK "Arm Processor"

SetOutPath "$INSTDIR"
File "NETCFv2.ppc.armv4.ini"
File "NETCFv2.ppc.armv4.cab"
StrCpy $0 "$INSTDIR\NETCFv2.ppc.armv4.ini"

Call InstallCAB
${Break}

${Case} ${PROCESSOR_ARCHITECTURE_ARM4I}
MessageBox MB_OK "Arm4i Processor"

SetOutPath "$INSTDIR"
File "NETCFv2.wm.armv4i.ini"
File "NETCFv2.wm.armv4i.cab"
StrCpy $0 "$INSTDIR\NETCFv2.wm.armv4i.ini"

Call InstallCAB
${Break}

/* Not supporting this yet
${Case} ${PROCESSOR_ARCHITECTURE_SHX}
; MessageBox MB_OK "Shx Processor"
${Break}
*/

/* Not supporting this yet
${Case} ${PROCESSOR_ARCHITECTURE_MIPS}
;MessageBox MB_OK "Mips Processor"
${Break}
*/

${Default}
;MessageBox MB_OK "Dont Know Processor"
${Break}
${EndSwitch}
${Else}
DetailPrint "error initializing rapi interface"
DetailPrint "make sure the device is connected"
${EndIf}
System::Call "rapi::CeRapiUninit()"
FunctionEnd


and i dont know about the way i'm setting this out either, basically before i call this function i am checking the ppc registry for .netCFv2 and if not installed it will call this function.
:eek:

4096 is definitely unknown, it's not ARM4I. That's a define used by the normal GetSystemInfo as well, so it can't be wrong. Try removing "i, " as I said in the reply above.