Perl Win32 :: API - bağımlı DLL algılanmadı

Oct 18 2020

Bu perl betiği, test verilerini içerecek şekilde @ikegami paralel diziler sürümünden değiştirilmiştir.

Yürütme sırasında şu hata mesajıyla başarısız olur:

“Gsl.dll bilgisayarınızda eksik olduğundan program başlatılamıyor. Sorunu çözmek için programı yeniden yüklemeyi deneyin. "

Bununla birlikte, bir C programı PolyFit'i çalıştırdığında hatasız çalışır. Bunun kaynak kodu aşağıdaki perl betiğini izler.

gsl.dll, PolyFitGSL.dll ile aynı dizinde bulunur, D: / prjct / model / code / SRS1 / binaries /:


#  @ikegami parallel arrays version

use 5.014;
use strict;
use warnings;

use feature qw( state );

use Config  qw( %Config );
use Win32::API qw( );

use constant PTR_SIZE => $Config{ptrsize}; use constant PTR_PACK_FORMAT => PTR_SIZE == 8 ? 'Q' : PTR_SIZE == 4 ? 'L' : die("Unrecognized ptrsize\n"); use constant PTR_WIN32API_TYPE => PTR_SIZE == 8 ? 'DWORD64' : PTR_SIZE == 4 ? 'DWORD32' : die("Unrecognized ptrsize\n"); # local definitions my $fitorder = 3;
my @XVals = (1,2,3,4,5,6,7,8,9,10);
my @YVals = (12.36,12.32,12.31,12.37,12.44,12.44,12.5,12.46,12.48,12.51);


Win32::API::Type->typedef('uintptr_t' => PTR_WIN32API_TYPE);

my $dll = 'D:/prjct/model/code/SRS1/binaries/PolyFitGSL'; sub get_buffer_addr { unpack(PTR_PACK_FORMAT, pack('P', $_[0])) }

sub poly_fit {
   my ($xvals, $yvals, $fitorder) = @_; @$xvals == @$yvals or croak("Mismatch in the number of X vals and Y vals"); state $PolyFit;
   if (!$PolyFit) { my $adjusted_proto = '
         int __declspec PolyFit(
            int numPts,
            uintptr_t xVals,
            uintptr_t yVals,
            int fitOrder,
            uintptr_t coef,
            uintptr_t fitVals,
            uintptr_t rSquared
         )
      ';
      
      $PolyFit = Win32::API::More->new($dll, $adjusted_proto) or die("Can't link to PolyFit: $^E\n");
     }
     
   my $n = @$xvals;

   my $xVals = pack("d$n",                 @$xvals); my $yVals     = pack("d$n", @$yvals);
   my $coef = pack('d'.( $fitorder + 1 ), ( 0 )x( $fitorder + 1 )); my $fit_vals  = pack("d$n", ( 0 )x( $n ));
   my $r_squared = pack('d', 0); my $rv = $PolyFit->Call( $n,
      get_buffer_addr($xvals), get_buffer_addr($yvals),
      $fitorder, get_buffer_addr($coef),
      get_buffer_addr($fit_vals), get_buffer_addr($r_squared),
   );

   # I'm assuming the return value indicates whether the call was successful or not?
   return if !$rv; } my ($coef, $fitVals, $r_squared) = poly_fit(
   \@XVals,
   \@YVals,
   $fitorder,
)
   or die("Error");
     

Bir girdi veri dosyası sağlandığında, bu C programı PolyFit çalıştırılırken herhangi bir hata olmaksızın başarıyla çalışır.

lang-C

// PolyFitFileData.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include <stdlib.h>
#include "..\PolyFitGSL\PolyFitGSL.h"
#include <time.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

int ReadSingleColDataFile(const char* filename, int numPts, int numHeaderRows, double* data)
{
    int i;
    double curNum;
    char line[32];
    FILE* fPtr;
    fopen_s(&fPtr, filename, "r");
    if (fPtr == NULL)
    {
        return 1;
    }

    for (i = 0; i < (numPts + numHeaderRows); i++)
    {
        if (fgets(line, 32, fPtr) != NULL)
        {
            if (i >= numHeaderRows)
            {
                curNum = strtod(line, NULL);
                data[i - numHeaderRows] = curNum;
            }
        }
    }

    return 0;
}

int main(int argc, char** argv)
{
    int i, n, resFit, lineNum;
    double* xVals;
    double* yVals;

    double* coef;
    double* estYVals;
    double* rSquared;

    FILE* fptr;
    int fitOrder=1;

    if (argc != 5)
    {
        printf_s("Pass in 4 args: \n(1) number of points \n(2) filename with data (Y values only, one per line, one header line)\n(3) Fit order\n(4) Output Filename (or empty string for none)");
        exit(-1);
    }

    if (fopen_s(&fptr, argv[2], "r") != 0) {
        printf("Error! opening input file");
        // Program exits if file pointer returns NULL.
        exit(-16);
    }

    n = atoi(argv[1]);
    fitOrder = atoi(argv[3]);

    xVals = (double*)malloc(n * sizeof(double));
    yVals = (double*)malloc(n * sizeof(double));

    if (fptr != NULL) {
        char line[100];
        lineNum = 0;
        while ((fgets(line, sizeof line, fptr) != NULL) && lineNum < (n + 1)) /* read a line from a file */ {
            if (lineNum > 0)
            {
                //then parse string and add double to list
                yVals[lineNum - 1] = atof(line);
                xVals[lineNum - 1] = (double)lineNum;
            }
            lineNum++;
        }

        fclose(fptr);
    }
    else {
        return -22;
    }

    coef = (double*)malloc((fitOrder + 1) * sizeof(double));
    estYVals = (double*)malloc(n * sizeof(double));
    rSquared = (double*)malloc(sizeof(double));
    resFit = PolyFit(n, xVals, yVals, fitOrder, coef, estYVals, rSquared);

    //I can print out results to file now here, or to screen....

    printf_s("Completed fit.  Result from PolyFit function was %d.\n", resFit);

    printf_s("Fit order: %d\n", fitOrder);
    printf_s("RSquared: %f\n", *rSquared);
    printf_s("Coefficients:\n");
    for (i = 0; i < fitOrder + 1; i++)
    {
        printf_s("[x%d] %f\n", i, coef[i]);
    }
    printf_s("%d Data points (x,y,yFit):\n", n);
    for (i = 0; i < n; i++)
    {
        printf_s("%f\t%f\t%f\n", xVals[i], yVals[i], estYVals[i]);
    }

    //if you pass in empty string "" then assume that you don't want to write to disk
    fptr = NULL;
    if (strlen(argv[4]) > 2)
    {
        if (fopen_s(&fptr, argv[4], "w") != 0) {
            printf("Error! opening file for output");
            // Program exits if file pointer returns NULL.
            exit(-16);
        }

        fprintf_s(fptr,"Fit order: %d\n", fitOrder);
        fprintf_s(fptr, "RSquared: %f\n", *rSquared);
        fprintf_s(fptr, "Coefficients:\n");
        for (i = 0; i < fitOrder + 1; i++)
        {
            fprintf_s(fptr, "[x%d] %f\n", i, coef[i]);
        }
        fprintf_s(fptr, "%d Data points (x,y,yFit):\n", n);
        for (i = 0; i < n; i++)
        {
            fprintf_s(fptr, "%f\t%f\t%f\n", xVals[i], yVals[i], estYVals[i]);
        }
        fclose(fptr);
    }

    free(coef);
    free(estYVals);
    free(rSquared);

    free(xVals);
    free(yVals);

    return 0;
}

Yanıtlar

ikegami Oct 19 2020 at 10:07

Bu bir Perl problemi değildir; bu, Windows'un DLL'lerinizi nerede bulacağını bilmesiyle ilgilidir. Bkz. Dinamik Bağlantı Kitaplığı Arama Sırası .

Komut dosyasının ve dolayısıyla DLL'nin bulunduğu dizin kullanılarak elde edilebilir.

use FindBin qw( $RealBin );

Diğer çözümlerin yanı sıra, mevcut dizini o dizine değiştirmeyi bulacaksınız.

chdir($RealBin);

ve PATH'a ekleyerek

$ENV{PATH} = "$RealBin;$ENV{PATH}";