如何在Pascal Script / Inno Setup中使用WinAPI中的PathCombine()?

时间:2015-07-28 03:28:02

标签: windows winapi inno-setup pascalscript

我正在试图弄清楚如何使用Pascal Script / Inno Setup中的WinAPI函数。我没有找到很多代码示例如何做到这一点,我不是一个Pascal程序员。这是我到目前为止所做的:

导入功能

public class InstallAPK extends AsyncTask<Void,Integer,Void> {

ProgressDialog progressDialog;
int status = 0;

private Context context;
public InstallAPK(Context context, ProgressDialog progress){
    this.context = context;
    this.progressDialog = progress;
}

public void onPreExecute() {
    if(progressDialog!=null)
        progressDialog.show();
}

@Override
protected Void doInBackground(Void... arg0) {
    try {
        URL url = new URL(context.getString(R.string.kodi_apk_link));
        HttpURLConnection c = (HttpURLConnection) url.openConnection();
        c.setRequestMethod("GET");
        c.setDoOutput(true);
        c.connect();

        // getting file length
        int lenghtOfFile = c.getContentLength();
        Log.e("File length", ""+lenghtOfFile);

        File outputFile = new File(context.getFilesDir(), context.getString(R.string.kodi_apk_name));
        if(outputFile.exists()){
            if(outputFile.length() != lenghtOfFile)
                outputFile.delete();
            else {
                publishProgress(-1);
                final String libs = "LD_LIBRARY_PATH=/vendor/lib:/system/lib ";
                final String commands = libs + "pm install -r " + context.getFilesDir().getAbsolutePath() + "/"
                        + context.getString(R.string.kodi_apk_name);
                installApk(commands);
                return null;                    
            }
        }
        FileOutputStream fos = new FileOutputStream(outputFile);

        InputStream is = c.getInputStream();
        //i tried both, with and without buffered reader
        BufferedInputStream bufferedInputStream = new BufferedInputStream(is);

        byte[] buffer = new byte[1024];
        int len1 = 0, total=0;

        if (lenghtOfFile != -1)
        {
            buffer = new byte[lenghtOfFile];
            do {
                len1 += bufferedInputStream.read(buffer, len1, lenghtOfFile-len1);
                publishProgress((int)((len1*100)/lenghtOfFile));
            } while (len1 < lenghtOfFile);
        }

        //I was using this code before, but it's not working too
        /*while ((len1 = is.read(buffer)) != -1) {
            total += len1;
            publishProgress((int)((total*100)/lenghtOfFile));
            fos.write(buffer, 0, len1);
        }*/
        fos.flush();
        fos.close();
        bufferedInputStream.close();
        is.close();

        //Log.e("Directory path", myDir.getAbsolutePath());

        publishProgress(-1);

        final String libs = "LD_LIBRARY_PATH=/vendor/lib:/system/lib ";

        final String commands = libs + "pm install -r " + context.getFilesDir().getAbsolutePath() + "/"
                + context.getString(R.string.kodi_apk_name);

        installApk(commands);


    } catch (FileNotFoundException fnfe) {
        status = 1;
        Log.e("File", "FileNotFoundException! " + fnfe);
    }

    catch(Exception e)
    {
        Log.e("UpdateAPP", "Exception " + e);
    }
    return null;
}

protected void onProgressUpdate(Integer... progress) {
    if(progress[0]!=-1) {
        // setting progress percentage
        progressDialog.setProgress(progress[0]);
    } else {
        progressDialog.setIndeterminate(true);
        progressDialog.setMessage("Installing Kodi...");
    }
}

public void onPostExecute(Void unused) {
    if(progressDialog!=null) {
        progressDialog.dismiss();
    }
    if(status == 1)
        Toast.makeText(context,"App Not Available",Toast.LENGTH_LONG).show();
    else
        Toast.makeText(context,"Successfully installed the app",Toast.LENGTH_LONG).show();

    Intent LaunchIntent = context.getPackageManager().getLaunchIntentForPackage(context.getString(R.string.kodi_apk_package));
    if(LaunchIntent!=null)
        context.startActivity(LaunchIntent);
    else
        Toast.makeText(context, "Error in installig Kodi, Try again.", Toast.LENGTH_LONG).show();
}

private void installApk(String commands) {
    try {
        Process p = Runtime.getRuntime().exec("su");
        InputStream es = p.getErrorStream();
        DataOutputStream os = new DataOutputStream(p.getOutputStream());

        os.writeBytes(commands + "\n");

        os.writeBytes("exit\n");
        os.flush();

        int read;
        byte[] buffer = new byte[4096];
        String output = new String();
        while ((read = es.read(buffer)) > 0) {
            output += new String(buffer, 0, read);
        }

        Log.v("AutoUpdaterActivity", output.toString());

        p.waitFor();

    } catch (IOException e) {
        Log.v("AutoUpdaterActivity", e.toString());
    } catch (InterruptedException e) {
        Log.v("AutoUpdaterActivity", e.toString());
    }
}

}

并像这样使用它:

function PathCombine (
    pszPathOut : PChar;
    pszPathIn  : PChar;
    pszMore    : PChar
) : PChar;
  external 'PathCombineA@Shlwapi.dll stdcall';

输出是这样的:

enter image description here

预期输出为:

  

C:\一个\ 2

我很确定我在内存中访问垃圾值,但我不知道为什么,我该如何解决?

2 个答案:

答案 0 :(得分:2)

您没有指定是否使用Ansi或Unicode版本的Inno Setup。

但这应该适用于任何一个版本:

function PathCombine(
   pszPathOut : PAnsiChar;
   pszPathIn  : PAnsiChar;
   pszMore    : PAnsiChar
) : PAnsiChar; external 'PathCombineA@Shlwapi.dll stdcall';

function InitializeSetup(): Boolean;
var 
  a, b, c: AnsiString;
begin
   SetLength(c, 256); { soon it gets working I'll switch to use MAX_PATH instead of }
   a := 'C:';
   b := 'one\two';
   PathCombine(c, a, b);
   MsgBox(c, mbInformation, MB_OK);
   Result := True;
end;

虽然我强烈建议您改为使用Unicode version of Inno SetupPathCombineW

function PathCombine(
   pszPathOut : string;
   pszPathIn  : string;
   pszMore    : string
) : Cardinal; external 'PathCombineW@Shlwapi.dll stdcall';

function InitializeSetup(): Boolean;
var 
  a, b, c: string;
begin
   SetLength(c, 256); { soon it gets working I'll switch to use MAX_PATH instead of }
   a := 'C:';
   b := 'one\two';
   PathCombine(c, a, b);
   MsgBox(c, mbInformation, MB_OK);
   Result := True;
end;

请注意,Inno Setup缺少PWideChar类型。虽然它可以封送stringLPTSTRPWideChar)函数参数,但它不能封送LPTSTR返回值。所以我使用Cardinal作为返回类型。它与指针(对于char)具有相同的大小,因此堆栈将匹配。我们实际上并不需要返回的值。

答案 1 :(得分:-1)

我认为(虽然我还没有使用 Pascal / Delphi 一段时间)问题是 C “字符串” (char * 0 基于索引,而 Pascal 字符串 1 基于索引(字节 0 用于存储长度)。

因此,如果您将s变量声明为:

s: array[0..255] of Char;  //Don't forget to change it to MAX_PATH afterwards

它应该有用。也可以像这样使用PathCombine函数:

PathCombine(s, a, b);

无需将其结果(与s相同)分配给另一个变量(无论如何都不会使用)。

相关问题